question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

programmatically updating title or tags works inside ngOnInit, but not within subscribe callback function.

See original GitHub issue

I’m submitting a … (check one with “x”)

[x] bug report => check the README and search github for a similar issue or PR before submitting
[ ] support request => check the README and search github for a similar issue or PR before submitting
[ ] feature request

Current behavior

Neither this.meta.setTag('description', 'updated description'); or this.meta.setTitle('updated title'); seem to work inside of a subscribe function of an http request to a REST API. Expected/desired behavior

It should use the default values of the metaService as defined here: https://github.com/nglibs/meta#appmodulets-2 until the http request finishes and the subscribe function is called, then it should use the updated data as defined by the setter functions. Minimal reproduction of the problem with instructions

Follow the above description

What is the motivation / use case for changing the behavior?

I have data from the server that needs to be put into the meta and title tags for better seo with Google. Please tell us about your environment:

  • Angular version: 2.0.X

angular-cli: 1.0.0-beta.26 node: 6.9.3 os: darwin x64 @angular/common: 2.4.5 @angular/compiler: 2.4.5 @angular/core: 2.4.5 @angular/forms: 2.4.5 @angular/http: 2.4.5 @angular/material: 2.0.0-beta.1 @angular/platform-browser: 2.4.5 @angular/platform-browser-dynamic: 2.4.5 @angular/router: 3.4.5 @angular/compiler-cli: 2.4.5

  • Browser: [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ]
  • Language: [all | TypeScript X.X | ES6/7 | ES5] TypeScript
  • Node (for AoT issues): node --version =

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:8 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
colin-daviscommented, Mar 30, 2017

So I was having some issues with this as well but I found a pretty good solution.

First the issue: NavigationEnd is called as soon as ngOnInit() finishes and does not wait for subscriptions to complete (and it shouldn’t). Even deferred function won’t add data from the subscriptions. As a hack you could add a function to manually update them when the subscription is done, however, this would be bad SEO as the values would load and then be updated (It’s possible that the googlebot would only read the first values and move on).

The Best Solution: (No changes to @nglibs/meta needed). You need to load the data before the page is rendered. You can do this using the resolver in your routing module. Read this: https://angular.io/docs/ts/latest/api/router/index/Resolve-interface.html Then on your page you can get the data by:

constructor(private route: ActivatedRoute) {}

ngOnInit(){
    this.product = this.route.snapshot.data['product'];  
}

This ensures that the subscription is completed before the component is loaded and all of the metadata can be set immediately after in ngOnInit().

Note: you do not need to use the defer method for this.

@kblestarge Let me know if any of this is unclear and best of luck. @fulls1z3 Awesome job on this project.

1reaction
fulls1z3commented, Mar 31, 2017

Hi @kblestarge, @Raydaq-git. First of all I’d like to thank to @Raydaq-git for coming up quickly and offering such a working solution as well as both your appreciation.

The use of resolver would definitely work in most cases, no doubts. However, I’d like to offer another alternative too: the callback function - which might be a slightly more elegant way to handle this.

I need to clarify that, it could be the case only if you’re using a certain REST call to fetch the data. I mean, there’s a generic service (could be a SEO service returning page titles) that you invoke by passing the page id/key/etc as argument.

Well, if you look at the app.module.ts on @nglibs/example-app, you’ll notice that the metaFactory contains the (key: string) => translate.get(key) as a callback. It means, the value that the meta property contains gets resolved using that callback function.

And, if you look at the config.json, home.routes.ts, and about.routes.ts you’ll notice keys/values like "defaultPageTitle": "DEFAULT_TITLE", "defaultMetaDescription": "DEFAULT_DESC", as well as:

  {
    path: '',
    component: HomeComponent,
    data: {
      meta: {
        title: 'PUBLIC.HOME.PAGE_TITLE',
        override: true,
        description: 'PUBLIC.HOME.META_DESC'
      }
    }
  }

In this example app, the callback function is the translate.get (thanks to @ocombe, for his awesome project ngx-translate). ngx-translate uses these keys are to retrieve translations of meta information on en.json and on tr.json.

In your case, a more or less a similar approach should work:

metaFactory

callback: (key: string) => seoService.getEntityBySeoName(key)

This way, you won’t need to call meta.setTitle/meta.setTag within the subscriptions. Simply pass the keys to a generic service which handles retrieval of seo data, and you’re done 😉

Meantime, I feel that you’re getting the meta info on the entity level - not using a generic method. The callback approach might not work if you stick using separate methods for every object. But there might be a way to make it generic - it’s up to the architecture of your project.

Anyway, please feel free to ask anything you need, I’ll be glad to provide help as far as in me lies.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Angular 6 View is not updated after changing a variable within ...
As far as I know, Angular is only updating the view, if you change data in the "Angular zone". The asynchronous call in...
Read more >
48 answers on StackOverflow to the most popular Angular ...
We have to import OnInit in order to use like this (actually implementing OnInit is not mandatory but considered good practice):
Read more >
Heading Off 11 Common Angular Application Design, Best ...
One of the most common patterns seen in Angular components is to subscribe to an Observable and display the resulting data in a...
Read more >
Loading Components Dynamically in an Angular App
A tutorial that shows how to create an Angular app with dynamic component loading.
Read more >
ion-modal: Ionic Mobile App Custom Modal API Component
ion-modal is a dialog that appears on top of mobile app content, and must be ... a JavaScript framework will not destroy the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found