I like the idea of resolver
s.
You can say that:
- for a given route you expect some data to be loaded first
- you can just have a really simple component with no observable (as retrieving data from this.route.snapshot.data
)
So resolvers makes a lot of sense.
BUT:
- You're not changing the URL and displaying your requested component until you receive the actual response. So you can't (simply) show the user that something is happening by rendering your component and showing as much as you can (just like it's advised to, for the shell app with PWA). Which means that when having a bad connection, your user may have to just wait without visual indication of what's happening for a long time
- If you are using a resolver on a route with param, let's take as example users/1
, it'll work fine the first time. But if you go to users/2
, well nothing will happen unless you start using another observable: this.route.data.subscribe()
So it feels like resolvers might be helpful retrieving some data BUT in practice I wouldn't use them in case there's a slow network and especially for routes with params.
Am I missing something here? Is there a way to use them with those real constraints?
The resolver gives you a hook near the start of router navigation and it lets you control the navigation attempt. This gives you a lot of freedom, but not a lot of hard and fast rules.
You don't have to use the result of the resolve in your component. You can just use the resolve as a hook. This is my preferred way of using it for the reasons you've cited. Using the result in your component is much simpler, but it has those synchronous trade-offs.
For example, if you're using something like Material or Cdk, you could dispatch a "loading" dialog to display a progress indicator at the start of the resolve, then close the dialog when the resolve concludes. Like so:
If you're using
ngrx
, you could do something similar by dispatching actions while the resolve is in progress.When you're using the Resolve guard in this fashion, there's not a particularly strong reason to use the Resolve guard instead of the CanActivate guard. That choice comes down to semantics. I find it more obvious to gate authentication on CanActivate and initiate data retrieval from Resolve. When those topics are allowed to blend it becomes an abritrary choice.
This is why I would use a resolver:
myapp.com/lists
, navigate to one element of the listmyapp.com/lists/1
, showing the details of that element, no need to fetch the data, already done by the search. Then let suppose you navigate directly tomyapp.com/lists/1
you need to fetch and then navigate to the componentThink to the resolver as a middleware between your app and your component, you can manage the loading view in the parent component, where
<router-outlet>
is included.Resolver: It gets executed even before the user is routed to new page.
Whenever you need to get the data before the component initialization, the right way to do this is to use resolver. Resolver acts synchronously i.e. resolver will wait for async call to complete and only after processing the async call, it will route to the respective URL. Thus, the component initialization will wait till the callback is completed. Thus, if you want to do something (service call), even before the component is initialized, you have come to right place.
Example Scenario: I was working on the project where user would pass the name of file to be loaded in the URL. Based on the name passed we would do the async call in ngOnInit and get the file. But the problem with this is, if user passes the incorrect name in URL, our service would try to fetch the file which does not exists on the server. We have 2 option in such scenario:
Option 1: To get the list of valid filenames in ngOnInit, and then call the actual service to fetch the file (If file name is valid). Both of these calls should be synchronous.
Option 2: Fetch the list of valid filenames in the resolver, check whether filename in URL is valid or not, and then fetch the file data.
Option 2 is a better choice, since resolver handles the synchronicity of calls.
Important:: Use resolver when you want to fetch the data even before the user is routed to the URL. Resolver could include service calls which would bring us the data required to load the next page.