In these Angular NgRX story series I am going to cover specific parts of the Angular application which are not obvious to implement with the NgRx library.
NgRx is RxJS powered state management for Angular applications, inspired by Redux. It helps us to manage a state of the application, and there are some benefits over the standard service-oriented approach.
If you are lazy to read a step-by-step explanation, check Github repo example for the full implementation.
We are writing an Angular app with the NgRX approach. We want to be sure that before we can enter to Profile page we have data to show in this component. You can check the standard implementation of the Route Resolver from official docs. And we will go forward to understand how to achieve that with the NgRX State management.
Let’s take a look at ProfileComponent
. It’s a classical subscription to Observable been returned by network call from ApiService
. No matter what’s for ProfileComponent
is using this data, let’s assume we need to be sure data exists before we enter the component.
My personal preferences to keep files in feature oriented structure. So we will place new files to the same folder as our ProfileComponent
were placed. Here is a new structure of folder after we’ve created profile.reducer.ts
and profile.actions.ts
.
Profile folder structure
Taking a look at profile.actions.ts
IProfileActions
— list of actions which we will use to manipulate data related to Profile entity. In case want to extend functionality, we can add such actions as PORFILE_INIT
, PROFILE_CHANGE
etc. For now, we are fine with action which will trigger for updating of the Profile data.UpdateAction
— is single action type which we define to describe an action of getting new data (IProfileData
type).Now let's handle this action in the profile.reducer.ts
IProfileState
— to describe how are we going to extend basic reducer of application.initialState
— default value for ProfileData
reducer
— processes single action (UPDATE) to describe state changes after the action was triggered with some payloadWe compose root state of the application by adding reducer Object to all reducers
(LOC: 11 app.state.ts
).
And the last thing — we defining the StoreModule with the reducers we’ve created before storeReducers
(LOC: 8 app.module.ts
).
Now, let’s put resolver on the route we want to wait until data will be loaded.
Continue by creating profile.resolver.ts
with the corresponding class as we name it on the LOC: 8 in app.routes.ts
above. This line is saying to wait for navigation to /profile
route until data will be resolved in the ProfileResolver
which we are going to implement in a second.
A newly created class implementing [Resolve](https://angular.io/api/router/Resolve)
interface which obliges us to define _resolve_
function. This function can return Promise, Observable or expected type directly.
Function **waitForProfileDataToLoad**
:
LOC 23: Subscribe store to listen for profile
object changes.
LOC 24: Map values to get the only profileData
from the general profile
object
LOC 25: Ignore all triggers where profileData
does not exist
LOC 26: take(1) — getting only first value, as long as we need single one to resolve route
Function **initProfileData**
:
Getting the first value of profile
object located in the store. If there is no value:
getProfileData()
UpdateAction
with the data
which we just got from serverWe’ve initialized data by getting it from the server, and dispatching new state for the application store. Meanwhile, we told our resolve function to listen for the store changes, and return Observable with the first nonempty ProfileData
it will find in the store.
Finally, we are getting profileData
from route snapshot, assuming it must exist there.
NgRx driven applications make very clear a data flow process through the application. I hope that will give you some patterns how to solve route resolving problem.
Here are few things you can also do to improve your application experience:
**initProfileData**
— could be moved or removed if you have some different places to init data.ProfileResolver
to return Boolean instead of data. Could be nice homework exercise to master this topic 😜.Thanks for reading! If you want me to write more similar stories recommend this post (by clicking the ❤ button).
Write your thoughts to comments and subscribe to my medium to find more stories.