Accessing resolved data in a component tree (Angular Router)

In this post, I want to bring up a technique for accessing and modifying resolved data which I found useful. I assume that reader has already used router, resolvers and knows what is the ReplaySubject.

New Angular Router v3 makes developer’s life much easier. Now there is a newly introduced pre-activation phase. It is designed to be used out of a component life-cycle and you can get control over an ongoing navigation via guards, asynchronously resolve your data and do whatever you need to do to accomplish components rendering.

We can get rid of the whole layer of complexity from the components — we are 100% sure that we’ll have all the data loaded and components are ready to be displayed. And that allows components to concentrate more on what they do really well — displaying content and catching events from the user.

Accessing data loaded on pre-activation phase

So, how does one access to a loaded data in a components tree?

Approach suggested by Angular team will look like this:

Here and below I assume that reader knows Angular in practice and very often all code that is obvious and not required for explanation is omitted: decorators, component parameters, etc.

If you have nested components you need to replace route with a route.parent where you need to repeat parent part required amount of times, depending on how deep your component in the components tree. And this part seems weird to me since a child knows about parents too much — and when we decide to add new layer that will brake everything.

That issue could be solved with Dependency Injection:

Here I defined a token CurrentPost and provided it using factory which extracts post stream from the current ActivatedRoute instance data. Then, when we need a post, we just inject CurrentPost and get a stream of loaded posts. For me that looks better now then specifying parents.

Modifying loaded data

Sometimes we want to modify loaded data in response to user’s action.

It’s obvious that we can’t modify data stored in activated route directly. The solution can be in extending above technique by wrapping resolved data into ReplaySubject like that:

And then when we need to modify CurrentPost , f.e. in memory, we just push next value:

Discussion

Those are simple techniques that can come handy in case when you are implementing simple logic which is not too complicated enough to create separate service.

Approach with ReplaySubject seems quite limited in terms of usage since it always requires the previous state of data every time before you use it. And to make it more flexible one can use more complex data organisation, f.e. meta-streams of operations and scan operator to get a stream of the result values (see https://github.com/ng-book/angular2-rxjs-chat/blob/master/app/ts/services/MessagesService.ts#L29 for example).

Conclusion

Default interface for accessing resolved data that Angular offers us doesn’t come handy when you want to get resolved data in a component located deep inside of components tree. You can assign a name for your resolved data and access them anywhere using the power of Angular Dependency Injector.