Overwrite a Service in a Component Subtree in Angular

Share this video with your friends

Social Share Links

Send Tweet
Published 7 years ago
Updated 8 months ago

Angular's hierarchical dependency allows us to overwrite a global service with a different class implementation for just a given sub-tree of the entire component tree of your application.

In this lesson we will take a look how this works, by registering the service on the component's child injector.

Instructor: [00:00] In this example here, we have the app component, which uses an app-person component inside its template. That app-person component injects here a people service, and that invokes here the people service getPerson method to display here a person.

[00:16] In turn, the getPerson method of that people service is quite simple. We have here a name. Basically, the getPerson simply returns an object and references this name here, which is then being shown here by our app-person component.

[00:28] What we would like to do now is to learn how we can scope a service to a certain component subtree, and to basically override it with a different kind of service. First of all, let's create here a new component. Let's call it woman.

[00:48] That woman component does very much the same as that person component does. It gets an instance of that people service. We have here also person property. Here we do this.person = this.people.getPerson. We obviously need here to inject that service, import it from the person service.

[01:11] Up here, let's do something like this. Let's say woman, just to know we are in a woman component here, and visualize that person again by simply showing its JSON structure.

[01:24] Let's jump back to the app component and visualize our new app-woman component. Let's have a look. Great. We see that we get the same value, because both component actually get an instance of that person service. Therefore, we will get the same value inside here.

[01:44] Let's now generate a new service, which we call woman service. We get here that woman service. What that woman service does is simply extending that people service. Then we basically override that getPerson method. We get here a person, and then we'll say person.name = Katie, and person.gender = female. Then, return that person.

[02:15] TypeScript complains here because we don't match the structure. Let's simply return here any, and we should be fine to go. This person service is actually registered here on our module, just as the people service, and so they're both exposed globally on our app module.

[02:35] Now let's go back to our woman component. You can see it still gets here the people service, and it also displays that same object from that people service, just as we expect. What we're going to do now is to basically override that people service.

[02:51] We do it not in the module level, but in the component level. We have providers property here, as well, which works identically as the one in the NgModule, but it is scoped to this component and its children. Let's demonstrate that.

[03:06] We create here the provide and say, whenever you see a people service, use the class woman service instead. If I save this, we will immediately see that this component here, which is displayed below the app component here, all get now an instance of an object, which comes from that woman service, which we just created here. Basically, we manipulate it in this way.

[03:30] Most interestingly also, if we go to the app component and we use that same app-person component here, and we bring it here nested into the template of our woman service, that same one will also get now the instance from that woman service. Although, inside app-person, we simply inject here the people service, just as before. We didn't change that to woman service.

[03:54] Here, we can basically see the hierarchical nature of the dependency injector in Angular. What happens here is that we have, at the very top, the app-root component, which is our app component. Then we have the app-person component which we gave it. Then we have the app-woman. Below, we did include, again, that app-person component.

[04:15] We have one module here, which is basically registered at the very top. Globally, we inject here that people service. Inside the component tree, at some level, we say whenever you see that people service, which is just what we did, use that woman service instead.

[04:32] From that component tree onwards, all its children and the component itself will then get an instance of this service, instead of the global people service.

Enoh Barbu
Enoh Barbu
~ 7 years ago

why do I need to override PeopleService with WomanService into providers section? Couldn't I just provide the WomanService directly into the constructor?

Juri Strumpflohner
Juri Strumpflohnerinstructor
~ 7 years ago

Hey. Sure. You could directly use the WomenService in the WomenComponent of my example. The point here though is that in this way you can overwrite/specialize an entire subtree of your component tree. As I explain in the example towards the end, even if we place the <app-person> inside the template of the WomenComponent, it will also get the instance of our WomanService (though in its constructor it fetches a PersonService).

So without even changing the implementation of the component, we can still influence how it fetches data via this mechanism.

Enoh Barbu
Enoh Barbu
~ 7 years ago

Ohh, now I see, the override will affect the current components and it's children that use the PeopleService. I've replayed the video and I saw that you did within WomanComponent. Thanks!

Juri Strumpflohner
Juri Strumpflohnerinstructor
~ 7 years ago

👌

Sreekanth
Sreekanth
~ 6 years ago

Hi guess, in this case (useExisting will also work in addition to PersonService)

{ provide : PeopleService, useExisting: WomanService } will work, since WomanService is available from the parent app-module injector.

Markdown supported.
Become a member to join the discussionEnroll Today