8
votes

I am using angular2 routing. When the user re-enters the value in the search field and clicks on search, the same component needs to be reloaded but with different route parameters.

<button (click)="onReload()">Search</button>

onReload() {
this.router.navigate(['results',this.location]);
}

This is my route path for my ResultsComponent

{ path:'results/:location', component:ResultsComponent}

This function changes the URL, but it does not reinitialize the component.

In angularjs, ui-router I could achieve it like this.

$state.go($state.current, location, {reload: true});

How do I do this in angular4?

3
we have the same problem :(vistajess
@vistajess Do tell me if you find a solution.CKA

3 Answers

4
votes

You need to perform the initialization logic within the subscription call back function within the subscription call back function of the route.params observable stream.

In your component class

@Component({
  ...
})
export class MyComponent implements OnInit {

   myLocation:string;

   constructor(private route:ActivatedRoute) {}

   ngOnInit() {
     this.route.params.subscribe((params:Params) => {
        this.myLocation = params['location'];
        // -- Initialization code -- 
        this.doMyCustomInitialization();
     }
   }

   private doMyCustomInitialization() {
       console.log(`Reinitializing with new location value ${this.location}`);
   }
}

On a different note, if you need to resolve data based on the value of 'location' you should use a resolve guard which resolves the data before the component is created. See https://angular.io/guide/router#resolve-guard for more information regarding resolve guards and routing.

Here's a working plunkr. https://plnkr.co/edit/g2tCnJ?p=preview

3
votes

EDITED

The angular way of telling the router to do this is to use onSameUrlNavigation as of angular 5.1

But I had to solve this issue in a different way(Stackblitz), by subscribing to route events and actually calling a custom reInit method.

The trick is to add all subscriptions to the same object and then unsubscribe ONLY when ngOnDestroy is called by angular, and doing the rest of your template vars change from the custom destroy method...

    public subscribers: any = {};

    constructor(private router: Router) {
    /** 
      * This is important: Since this screen can be accessed from two menu options 
      * we need to tell angular to reload the component when this happens.
      * It is important to filter the router events since router will emit many events,
      * therefore calling reInitComponent many times wich we do not want.
      */   
      this.subscribers._router_subscription = this.router.events.filter(evt => evt instanceof NavigationEnd).subscribe((value) => { 
        this.reInitComponent();
      });
    }

    reInitComponent() {
        this.customOnDestroy();
        this.customOnInit();
    }

    customOnInit() {
        // add your subscriptions to subscribers.WHATEVERSUB here
        // put your ngOnInit code here, and remove implementation and import 
    }

    customOnDestroy() {
      // here goes all logic to re initialize || modify the component vars  
    }

    /**
     * onDestroy will be called when router changes component, but not when changin parameters ;)
     * it is importatn to unsubscribe here
     */
     ngOnDestroy() {  
       for (let subscriberKey in this.subscribers) {
          let subscriber = this.subscribers[subscriberKey];
          if (subscriber instanceof Subscription) {
            subscriber.unsubscribe();
          }
        }
     }

Note that if you implement lifecylce hook ngOnInit, you should remove it and implement a custom method like in the example.

I added the unsubscription method because of this angular bug. Angular should actually automatically unsubscribe from router.events when destroying the component, but since this is not the case, if you do not unsubscribe manually you will end up calling http requests(for example) as many times as you entered the component.

2
votes

https://angular-2-training-book.rangle.io/handout/routing/routeparams.html

In your component you need to subscribe to the params in order to detect if they are changed.