If in the constructor you subscribe to the active route, ngInit will be called every time the router navigates to that page.
ngOnInit() is called once for every method. There is no way to make it being called multiple times.
Angular router traverses the URL tree and matches the URL segments against the paths configured in the router configuration. If a URL segment matches the path of a route, the route's child routes are matched against the remaining URL segments until all URL segments are matched.
To navigate a relative path with the Router. navigate method, you must supply the ActivatedRoute to give the router knowledge of where you are in the current route tree. After the link parameters array, add an object with a relativeTo property set to the ActivatedRoute .
You can inject the ActivatedRoute
and subscribe to params
constructor(route:ActivatedRoute) {
route.params.subscribe(val => {
// put the code from `ngOnInit` here
});
}
The router only destroys and recreates the component when it navigates to a different route. When only route params or query params are updated but the route is the same, the component won't be destroyed and recreated.
An alternative way to force the component to be recreated is to use a custom reuse strategy. See also Angular2 router 2.0.0 not reloading components when same url loaded with different parameters? (there doesn't seem to be much information available yet how to implement it)
You could adjust the reuseStrategy on the Router.
constructor(private router: Router) {
// override the route reuse strategy
this.router.routeReuseStrategy.shouldReuseRoute = function() {
return false;
};
}
I have used the following and it worked.
onButtonClick() {
this.router.routeReuseStrategy.shouldReuseRoute = function () {
return false;
}
this.router.onSameUrlNavigation = 'reload';
this.router.navigate('/myroute', { queryParams: { index: 1 } });
}
Do you probably need reloading page? This is my solution: I've changed the @NgModule (in app-routing.module.ts file in my case) :
@NgModule({
imports: [RouterModule.forRoot(routes, {onSameUrlNavigation: 'reload'})] })
Here is a collection of the best ideas on this page with more information
Solution 1 - Use params subscription:
Tutorial: https://angular-2-training-book.rangle.io/routing/routeparams#reading-route-parameters
Docs: https://angular.io/api/router/ActivatedRoute#params
In each of your routing components that use param variables include the following:
import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
// ...
@Component({
// ...
})
export class MyComponent implements OnInit, OnDestroy {
paramsSub: Subscription;
// ...
constructor(activeRoute: ActivatedRoute) {
}
public ngOnInit(): void {
// ...
this.paramsSub = this.activeRoute.params.subscribe(val => {
// Handle param values here
});
// ...
}
// ...
public ngOnDestroy(): void {
// Prevent memory leaks
this.paramsSub.unsubscribe();
}
}
Some common issues with this code is that subscriptions are asynchronous and can be trickier to deal with. Also you can't forget to unsubscribe on ngOnDestroy or else bad things can happen.
Good thing is that this is the most documented and common way to handle this problem. There's also a performance improvement doing it this way since you are reusing the template instead of destroying and recreating each time you visit a page.
Solution 2 - shouldReuseRoute / onSameUrlNavigation:
Docs: https://angular.io/api/router/ExtraOptions#onSameUrlNavigation
Docs: https://angular.io/api/router/RouteReuseStrategy#shouldReuseRoute
Docs: https://angular.io/api/router/ActivatedRouteSnapshot#params
Find where RouterModule.forRoot
is located in your project (normally found in app-routing.module.ts or app.module.ts):
const routes: Routes = [
// ...
];
// ...
@NgModule({
imports: [RouterModule.forRoot(routes, {
onSameUrlNavigation: 'reload'
})],
exports: [RouterModule]
})
Then in AppComponent add the following:
import { Component, OnInit} from '@angular/core';
import { Router } from '@angular/router';
// ...
@Component({
// ...
})
export class AppComponent implements OnInit {
constructor(private router: Router) {
}
ngOnInit() {
// Allows for ngOnInit to be called on routing to the same routing Component since we will never reuse a route
this.router.routeReuseStrategy.shouldReuseRoute = function() {
return false;
};
// ...
}
// ...
}
Last, in your routing components you can now handle param variables like this:
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
// ...
@Component({
// ...
})
export class MyComponent implements OnInit {
// ...
constructor(activeRoute: ActivatedRoute) {
}
public ngOnInit(): void {
// Handle params
const params = +this.activeRoute.snapshot.params;
// ...
}
// ...
}
Common issues with this solution is that it isn't common. Also you are changing the default behavior of the Angular framework, so you can run into issues people wouldn't normally run into.
Good thing is that all your code is synchronous and easier to understand.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With