In my application I retrieve all data in the "Items-Overview-Component" in the constructor. (router path: "/items"
).
// Items-Overview-Component
constructor(private store: Store<fromReducer.State>) {
this.store.dispatch(loadItems());
}
When clicking on an item entry, I navigate to "/items/:id"
. Then I retrieve the details from the store using the :id
.
// Item-Details-Component
constructor(private store: Store<fromReducer.State>) {
this.item$ = this.store.pipe(select(getItemDetails));
}
So far a very clear vanilla use case for an Angular project.
However, if the user navigates "hard" to a URL with a specific item (e.g. "/items/741"
), then the store is empty and no details can be retrieved.
How can I reload the data in NGRX "on demand"? Is there perhaps a one-time lifecycle hook that I should react to here?
BTW: I also use @ngrx/router-store
The pattern you want is most likely to use a guard on the /items
route, instead of relying on the Items-Overview-Component
to trigger loading items.
It could look like:
@Injectable({
providedIn: 'root',
})
export class ItemsGuard implements CanActivate {
constructor(
private store: Store<AppState>
) {}
public canActivate(): Observable<boolean> {
this.store.dispatch(loadItems()); // immediately trigger loading items
return this.store.select(getItems).pipe(
filter(items => !!items && items.length) // wait until the selector emits some non-empty items list
mapTo(true) // as soon as the items are present, allow the navigation event to complete
);
}
}
Then you can use it in your routes file like this:
path: 'items',
canActivate: [ItemsGuard],
....
children: [
// '/:id' route goes here
]
Since items/:id
is configured as a child route of /items
, ItemsGuard
will trigger in both cases, even if after page refresh you directly enter /items/123
without ever entering /items
.