jessepinho
jessepinho

Reputation: 5782

Angular2 router's navigateByUrl() not calling ngOnInit()

I have two Angular mini-apps on the same page. (Long story.) One is a navigation app, and one is the main app. I'm using the latest Angular router, based on angular/vladivostok.

It appears that the Angular router in one app (e.g., nav) does not respond to URL changes instantiated by the other app (e.g., the main app). So I've created a RouterSynchronizer1 class that I provide to both apps. It listens to both routers' NavigationEnd events. When one router (let's call it the "source") has an event, it calls navigateByUrl on the other router (let's call it the "subscriber").

This works fine for the most part. However, it doesn't call ngOnInit on the components of the subscriber.

I've created a Plunk to demonstrate this, based on the live example from Angular's official Routing & Navigation guide. Note that when you click the "Crisis Center" and "Heroes" links in the main app, ngOnInit is not called on the corresponding child components in the nav component. However, when you click those links in the nav component, ngOnInit is called on those child components, but not on the child components of the main app (which results in the lists of heroes/crisis centers being empty).

Any ideas? Thanks!

1 RouterSynchronizer class:

import { Inject } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';

interface ISubscriber {
  id: string;
  router: Router;
}

export class RouterSynchronizer {
  private subscribers: ISubscriber[] = [];

  connect(id: string, router: Router): void {
    this.subscribers.push({ id, router });
    this.startPublishing(id, router);
  }

  private startPublishing(source: string, router: Router): void {
    router.events.subscribe(route => {
      if (route instanceof NavigationEnd) {
        this.subscribers.forEach(subscriber => {
          if (subscriber.id === source || subscriber.router.url === route.urlAfterRedirects) {
            // Prevent infinite loops.
            return;
          }

          subscriber.router.navigateByUrl(route.urlAfterRedirects);
        });
      }
    });
  }
}

Upvotes: 2

Views: 5774

Answers (2)

jessepinho
jessepinho

Reputation: 5782

I figured it out! Apparently, I needed to use a zone. See the new Plunk for implementation.

The problem (I think!) is that my RouterSynchronizer class was instantiated and provided outside the Angular context. So it wasn't in an Angular zone when it pushed changes to the routers via navigateByUrl. Once I wrapped the navigateByUrl call in a zone provided by the app, it worked :)

Upvotes: 3

Ron
Ron

Reputation: 209

You have to implement OnInit like so:

import { Component, OnInit } from '@angular/core';

@Component({
    selector: 'nav-heroes',
    template: `<span *ngIf="hasRunOnInit">ngOnInit has run in NavCrisisCenterComponent</span>`,
})

export class NavCrisisCenterComponent implements OnInit {
    private hasRunOnInit: boolean;

    ngOnInit() {
    this.hasRunOnInit = true;
}
}

Upvotes: -1

Related Questions