How to use Angular route resolvers with NgRx store

Fetch data while navigating using NgRx store

Faid Affandi
5 min readNov 2, 2021

Angular resolver is a solution to manage url route parameters which allows to preload data when navigating to a page.

The Angular initial design for resolvers is independent from any centralized state management. So, when it comes to use resolvers with state management library such as NgRx store, it raises design questions and implementation pain points.

In this article, I propose a design and an implementation of resolvers to manage route parameters in an NgRx store based application.

✋Use case

NgRx store is a well known solution to manage the different source of data of an Angular application (server, url, local storage …).

One important challenge with the state management is to use the route parameters as the source of truth while keeping the store as the source of data for your components.

The design I propose applies when you want to use Angular resolver to retrieve the data needed to activate a route, with an NgRx store based application.

😏The design

NgRx store and facade (reminder)

We use NgRx store with Facade which expose our Store’s features to our components.

NgRx State management lifecycle + Facade

Facade are Angular services, exposing functions and observables which map actions and selectors of our Store.

The Resolver

In this scenario, our route url contains a parameter corresponding to an entity id. The role of our resolver is to retrieve this entity data by doing a call to the backend, and make it accessible for the rest of the application.

Entity id resolver

To make the entity accessible for the rest of the application, the resolver saves the entity data in the store using the functions defined in the Facade.

Router and store

After the data have been retrieved and saved in the store, we read the route parameter values from the store, without duplicating values in the state, to keep the route url as the source of truth.

source of data : Router and Store

In this design, the components can still rely on the store as the unique source of data, without knowing the implementation details. The route url is read by a dedicated selector, which keeps the router as the only owner of its parameter values.

In our example, the entity is saved in the store without its id. The full entity object is built in a selector, combining the id from the url with the content from the reducer.

💪The implementation

The Resolver

In this implementation, the resolver uses a route parameter to retrieve data from the backend, and save it in the store :

Entity id resolver

We first check if the entity is already loaded in the store. If it is the case, it’s not necessary to process the url id, and the resolver can activate the requested page with “of(null)” returned to the “resolve” function.

Otherwise, the resolver process the backend request and response, and forward the data to the store. In the case where the backend response is an error, maybe due to an invalid id, the application is redirected to a dedicated error page.

Note that the “resolve” function is expecting an object in case of success, which is supposed to be used by Angular components in the initial Angular resolver design. In our case, this object is returned to activate the requested page only, and not for components direct usage. The store stays the only source of data for our components.

Here is how this resolver is integrated to an Angular module :

Angular module with resolver

In this implementation example, the constants used for managing the routes are defined in an utility file (‘./constants’).

The Facade and the Store

The Facade implementation is simply mapping the actions and selectors used by the rest of the application :

feature Facade

Here the implementation of the action used to update the state :

feature action

And here is the implementation of the reducer where the entity is saved without its id, avoiding to have two sources of data for the entity id value :

feature reducer

NgRx provides tools to connect the Angular router to the store. Check this link for more details : @ngrx/router-store. Here is an implementation of the router selector, which allows to access route parameter values :

Router selector

And here is how the router selector is used in our feature selector to build the entity :

feature selector

🔥Bonus, “resolve from your state”

Sometimes, you have a parameter in your route which corresponds to a selected item in a list already saved in your store.

Example : in the Angular tour of hero, you can select a hero in a list, and be redirected to a “hero detail” page, with the id of your selection in the url.

In this case, you might prefer not to request the backend data from your resolver, as they are already loaded in your application. But you can still use the resolver to check if the route parameter has a valid value.

In this case, the resolver design is more like this :

resolve from state

And here is an implementation of this resolver :

Selected id Resolver

The resolver doesn’t even need to check the route parameters, as it is done in the router selector. In this implementation, the parameter value is just used in case of an invalid value, for the error page display.

Conclusion

With the proposed design, you can take advantage of Angular resolvers to manage the routing, and keep the consistency of your application using NgRx store as the only source of data for your Angular components.

Thank you for reading this article 😊

--

--

Faid Affandi

Software engineer | Angular dev | Software architecture and design