I\'ve spent more than 2 months but could not found a clear solution of how to proceed with angular universal. I\'ve already spent about 6 months in implementing angular univ
Stumbled upon this looking for same solution. Using a setTimeout worked for me. Make sure to refresh cache or use incognito mode or you'll miss seeing the metadata (I made this mistake). My research suggests that subscribe for API data must be waited upon before SSR renders page so observable must stay open (but I'm not an expert). https://angular.io/guide/observables. Also, the only way to make it work is to put the response from subscription right into metaService. I'll show what I mean in my code.
setTimeout( () =>
this.seo.setFromJson({
title: this.content.title,
image: this.content.main_image,
description: this.content.blog,
author: this.content.name,
keyword: ''
});
,0);
My code with solution:
this.publicFeedService.getPublicProfile(data).subscribe((response:any) => {
this.memberProfile = response[this.userId];
setTimeout( () =>
//Define the meta title using profile data
this.titleService.setTitle('The best investment ideas from ' + response[this.userId].firstName + ' ' + response[this.userId].lastName), 0);
setTimeout( () =>
//Define the meta tags using the user profile data
this.metaService.addTags([
{name: 'keywords', content: 'investing ideas, stock ideas, financial profile'},
{name: 'description', content: response[this.userId].about},
{name: 'robots', content: 'index, follow'}
]), 0);
Couldn't find an easy way to do it but here's a temporary/hacky solution provided by a GitHub user here and I'm quoting his answer directly:
//all imports
enableProdMode();
export const app = express();
const mysql = require('mysql');
const httpRequest = require("request");
// all other consts
app.engine('html', ngExpressEngine({
bootstrap: AppServerModuleNgFactory,
providers: [
provideModuleMap(LAZY_MODULE_MAP)
]
}));
//all other piece of code in server.ts
app.get('/*', (req, res) => {
res.render('index', {req, res}, (err, html) => {
if (html) {
//console.log(html);
// This is where you get hold of HTML which "is about to be rendered"
// after some conditional checks make a HTTP call
let url = 'http://....';
httpRequest.get(url, (error, response, body) => {
if(error) {
return console.log(error);
}
const respBody = JSON.parse(body);
if(respBody){
html = html.replace(/\$TITLE/g, respBody.title);
html = html.replace(/\$DESCRIPTION/g, respBody.description);
html = html.replace(/\$OG_META_KEYWORDS/g, respBody.metaKeywords);
html = html.replace(/\$OG_META_DESCRIPTION/g, respBody.metaDescription);
html = html.replace(/\$OG_DESCRIPTION/g, respBody.ogDescription);
html = html.replace(/\$OG_TITLE/g, respBody.ogTitle);
html = html.replace(/\$OG_IMAGE/g, respBody.img);
html = html.replace(/\$OG_SITE/g, respBody.ogSite);
}
res.send(html);
});
}
}
}
And in index.html, create template values as below:
<title>$TITLE</title>
<meta name="description" content="$DESCRIPTION"/>
<meta name="keywords" content="$OG_META_KEYWORDS" />
<meta name="metaDescription" content="$OG_META_DESCRIPTION"/>
<meta name="metaKeywords" content="$OG_META_KEYWORDS" />
<meta property="og:title" content="$OG_TITLE" />
<meta property="og:description" content="$OG_DESCRIPTION" />
<meta property="og:site_name" content="$OG_SITE" />
<meta property="og:type" content="website" />
<meta property="og:image" content="$OG_IMAGE" />
First Add all required meta tags in index.html file like this
Then update the meta tags in each required component, use meta.updateTag() as below
This one worked for me.
I try to create service to update but that not worked, its working only when meta update added in the same component.
I implemented setting title on Angular 2 Universal. It should be done using Renderer, like this:
1.Import Renderer inside of component:
import {Renderer } from '@angular/core';
2.Add dependency inside of constructor:
constructor
(
...
private renderer: Renderer
) {}
3.Use it now for setting title:
renderer.setText(renderer.selectRootElement('title'), value);