Very differently to AngularJS (v1.x), Angular now has a hierarchical dependency injector. That allows to specify service definitions as well as the service lifetime at various levels in our application. Whenever a service is requested, Angular will walk up the component tree and search for a matching definition. While in most cases that's perfectly fine, often you may want to take control over the dependency lookup. In this lesson we will learn how, by applying @Host()
, @SkipSelf()
and @Optional()
.
Instructor: [00:00] Here, we have an app component which internally uses an appPerson component. Our appPerson component is actually very simple. It gets here a logger service injected. Then whenever we click on a button here, that method, toDoLog, is called, which then logs out to the console.
[00:19] In fact, if you click here, we can see that we get the log message out here. Now, our logger service is actually quite simple here. We have a prefix, which gets passed into our logger service, and we have that log message, which logs out logger, then a prefix, and the message we passed in.
[00:36] In order to be able to construct this logger service, we have here a logger factory, which for instance, in the app module, we make use and we pass in here that this logger has been instantiated here by the app module.
[00:47] Now, Angular has a hierarchical dependency injector. As a result, if we go into the person component, whenever that person component requests here a logger service or another service to be injected, it will walk up the component tree.
[01:01] Basically, it checks here whether this component itself defines a logger service, which it doesn't. It walks up in its tree to the app root component, which is in our case here, the app component, which does nearly define the logger service.
[01:14] Ultimately, it finishes at the very global part here, which is our app module, which in fact, defines here a provider, which is our logger service. It passes in here that app module prefix. That's exactly why we get here that app module prefix printed out on our console.
[01:28] What happens in that provider here is not defined, so if we don't have any logger service? Let's quickly comment out this section here. If you take a look now at our dev tools console here, we see that we get an error, because Angular tells us there is no provider for our logger service, which our person component on our high end here requests.
[01:48] Now, in some scenarios, we could actually totally live even if the service is not provided. In fact, here, if you watch in the doLog method, we already take care that whenever the logger's not defined, we handle it differently.
[02:01] What Angular offers us is a so-called optional decorator here, which we can import. We import that from the Angular core package. What optional does is, whenever the logger service is not defined, it simply puts null into that variable here.
[02:18] We can check for that null value, and accordingly react. For instance, you can see how, "I don't have a logger method," is being printed out, because that logger is null, as well as when we write that log, there is, "Sorry, no logger available."
[02:31] Now, we just learned that the dependency injector is hierarchical. What we could actually do is, we could take that definition here of that logger service and define it here on our component. Let's comment it out here and add here app component. Similarly, we could also define it on our person component here.
[02:56] If you click that write log button here, we can see that we get the first logger the Angular independency injector can find, which in this case, is directly on our component here, so on the host itself. If we don't want to have that behavior, we can add another annotation here, which called skipSelf.
[03:13] Again, imported from the Angular core, which will skip here the search on our own host, but rather we go up onto the pattern. In fact, if we click here, we see that we get now the logger, which we have defined here on our app component.
[03:27] Very similarly, we can also tell that it should only search our host component. With that, we can basically specify here host. We'd search here now only on our host component here. In fact, we get again that person component logger.
[03:42] Also, if we don't define that person logger here -- if we take out that definition here -- we won't get that add component logger now. We rather will get that there's no logger service available because we don't continue to search upwards. We rather concentrate the search only on our host component here.
[04:02] The skipSelf, host, and optional are actually very powerful constructs because they allow us to take very fine grain control over which dependency injector injects the service into our components.