Search code examples
angularroutesangular2-observablesangular2-changedetection

angular 2 routing subscription change detection


Given this code:

ngOnInit() {
    this.apiService.getBlogPosts().subscribe(blogPosts => {
        this.allBlogPosts = blogPosts;

        this.changeDetector.detectChanges();
    }));
}

I am trying to understand why I am forced to use this.changeDetector.detectChanges();

The circumstances are that if I load my blog route for the first time, my posts load fine, if I route to another page (either another component or the same "blog" component to show the details of a particular post (e.g. 'blog/my-post')) then I route back to the "blog" component at the root ('blog/'), this time, the template fails to update with the posts. I can see in my Inspect, Network tab, that the route to get the posts is still working, console.log is showing that all seems well through-out, however the template fails to update unless I force change detection. Is this expected behavior? Can it be remedied? This seems strange...

Another thing worth noting is that both first time and the 3 time that I visit the "blog" component I use:

this.router.navigate([`/${url}`]);

To navigate to it... and this can not be helped...

Edit: the getBlogPosts() method is in my ApiService that I inject into my BlogComponent:

public getBlogPosts() : Observable<BlogPost[]> {
    return this.http.get(`${ environment.apiUrl }GetBlogPosts`, { headers: this.headers })
                    .map((response: Response) => <BlogPost[]>response.json());
}

Solution

  • Angular uses NgZone to get notified whenever the change detection cycle should be run. NgZone uses zone.js under the hood that intercepts all async operations like setTimeout, new Promise, XHR requests etc. So usually it works without any additional efforts from the developer.

    However, if you some operation that is not catched by zone.js you don't get change detection triggered and have to do that manually. But you can use NgZone to execute some action in the Angular zone meaning Angular will run change detection after the callback has finished executing.

    So in your case you can try something like this:

    this.routerSubject.subscribe((url: string) => { NgZone.run(() => this.router.navigate([/${url}]); });
    

    where NgZone can be injected into any Angular component or service:

    constructor(zone: NgZone) {}