I have an Angular component that needs to respond to route parameter changes that apply to the current page. For example, maybe I have the route page/:id
, and if the :id
changes, I want to respond by reloading the component's content.
Using the ActivatedRoute
's paramMap
, this is easy. While I'm on the page/:id
route, I can change the :id
in the URL and the application responds appropriately. When I navigate away from the page/:id
route, the component is destroyed, and no parameter changes are emitted.
However, if I try the same approach with @ngrx/router-store
, more route param changes are emitted than I actually want. I am getting the route params from the route that is being navigated to. This seems to happen because the router-store emits before my component gets destroyed.
I need a way to say "I only want the route params for this page, and as soon as this page is navigated away from, I need you to stop responding to route param changes." I thought this would be as easy as implementing a takeUntil(unsubscriber$)
which completes in my ngOnDestroy()
. However, that doesn't work because the next params emission happens before the ngOnDestroy()
gets called.
I imagine this behavior is by design, but I'm not sure how to overcome the problem I'm facing.
I've worked up a Stackblitz that demonstrates the issue.
What's the most elegant way to handle this situation using @ngrx/router-store
?
Working example using ActivatedRoute
export class MyComponent implements OnInit, OnDestroy {
unsubscriber$ = new Subject<void>();
constructor(public route: ActivatedRoute) {}
ngOnInit() {
this.route.paramMap
.pipe(takeUntil(this.unsubscriber$))
.subscribe(params => {
// reload data
});
}
ngOnDestroy() {
this.unsubscriber$.next();
this.unsubscriber$.complete();
}
}
Non-working example using router-store
export class MyComponent implements OnInit, OnDestroy {
unsubscriber$ = new Subject<void>();
constructor(public store: Store<State>) {}
ngOnInit() {
this.store
.pipe(select(selectRouteParams), takeUntil(this.unsubscriber$))
.subscribe(params => {
// reload data
// this code is being run even when this component is being navigated away from
});
}
ngOnDestroy() {
this.unsubscriber$.next();
this.unsubscriber$.complete();
}
}
Change your navigation action timing to
PostActivation
via the configuration object passed in toStoreRouterConnectingModule.forRoot
: