Thanks very much for this input. I think we are on the same page. (I can see that I failed to make clear that I was already assuming that an isLoading flag would part of store.state. This was hardly my own idea, as it’s in the official ngrx example-app.)
But to get to the heart of it:
I agree that the idea must be to make the component navigation immediate or direct or synchronous (whatever word fits best) so that it’s possible to run a spinner or other indication of “loading data” directly in the component. The trick is to make this work in the context of initiating the entire process from a navigate command so as to satisfy Victor’s imperative of starting from the router and thus allowing the URL to serialize the current data state.
We could stick with the idea of using the route guard. Because the guard must (to avoid asynchronicity) simply return a synchronous “true” in all cases, it doesn’t function as a guard at all, but only as a router “lifecycyle” hook to dispatch the action. Presumably something like this:
canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
if (this.lastState !== state) {
this.lastState = state;
this.store.sendAction({type: ‘QUERY_TALKS’, state});
}
return true;
}
I assume this will work, but it feels weak to me because, as I said, it’s using the guard as a mere hook.
The only alternative I’ve been able to figure out thus far that seems cleaner and simpler is to back up a step to the navigate call and use its returned promise to “then” the dispatch:
handleFiltersChange(filters: Filters): void { this.router.navigate([“/talks”, filtersToParams(filters)]).then( _ => {if(_) this.store.sendAction({type: ‘QUERY_TALKS’, state}) });
This is clean, but I am unsure about all of the consequences of inherently dispatching only after a successful navigation (depending on precisely what “successful” means to the router in this context). But if this approach makes sense, the whole process is now easy. The router.navigate method fully drives both navigating and dispatching the action needed to (ultimately) update store.state to reflect current filter values — without any asynchronous delay in change in router state.
How does this sound to you? This seems to me to be a very basic and important issue — ultimately getting to the fundamental questions of how the Angular router is to be ideally reconciled with any Redux-style store model.