Image for post
Image for post

@Self or @Optional @Host? The visual guide to Angular DI decorators.

Tomek Sułkowski
Feb 18, 2018 · 4 min read

Most of the time, when we need a service injected into our Angular classes, we can rely on the default service lookup that the framework provides. But that’s only, well, a default — and Angular also provides several other interesting possibilities. This article aims to collect all the options in a concise form.

The default

Let’s look at a sample KidComponent. It needs to know about toys that are being kept in a ToysService, so we inject that into its constructor (usually with a private modifier, here omitted for brevity).

By default Angular will first check if the component defines a dependency injector in its decorator. If it does (1.), the component (specifically: each of its instances) will receive its own instance of the service. If it doesn’t find in on the component, it will look for a parent injector (e.g. the parent component (2.), its ancestors etc), up the injectors tree and in the end it will stop on the application-wide instance of the service defined on a one of our NgModules. Unless it’s not even there, in which case we will get a “No provider” error.

@Self()

Image for post
Image for post

If we decorate the parameter with @Self(), it’s like there was only the first step of the previously discussed default behaviour. The only place allowed to find the injector is the component itself (3.). If it isn’t defined there…

@Optional()

… well, that would be an error, right? Yes, definitely (4.), but also not necessarily: if your component doesn’t absolutely need that service, you can decorate a parameter with the @Optional() decorator and in such case of no provider found, no error will occur. Instead Angular will set the value for our service tonull(5.)

You can set @Optional() in any other DI scenario discussed here as well.

If you’re following, in our Angular code, this could actually happen: constructor(@Optional() @Self() private readonly where: DidWeGoWrong){ .
I guess with great power comes great responsibility ¯\_(ツ)_/¯

@SkipSelf()

Image for post
Image for post

At this point, @SkipSelf() decorator should be, forgive the bad pun, self-explanatory. The behaviour is like the default — we’re looking up the injectors hierarchy, but this time skipping the first step of looking for a possible injector in the requesting component (6.)

@Host()

@Host() decorator makes Angular to look for the injector on the component itself, so in that regard it may look similar to the @Self() decorator (7.). But that’s actually not the end: if the injector is not found there, it looks for the injector up to its host component.

Wait, what?

There are two common scenarios where said host component is something different than our current class.

  • We’ve been looking at a Component as our example, but we may just as well have a Directive here instead. In that case it can be used on a Component that defines its injector and that component would be the directive’s host.
  • Or we can have our KidComponent projected into ParentComponent(by that <ng-content></ng-content> thingy). Then we also say that our component is being hosted by ParentComponent — and if ParentComponent provides ToyService and KidComponent does not, the @Host() decorator of that inner component would still get that service’s instance (8.)

Edit: there is a great in-depth write-up on the @Host() decorator by Max Wizard K that I highly recommend: https://blog.angularindepth.com/a-curios-case-of-the-host-decorator-and-element-injectors-in-angular-582562abcf0a.

Now I know what you are all eager to ask: can we have
constructor (@Host() @SkipSelf() @Optional() toys: ToysService) {...}?

The answer is: Yup, we can.

Practical note:
The post was quite theoretical (hopefully still useful) and I am working on a more hands-on article with some “oh-my-god-that’s-so-true!” examples, but in the meantime if you want to see these options in action I highly recommend this talk on forms https://youtu.be/CD_t3m2WMM8?t=1881 (timestamped to where the advanced DI stuff begins) given by Kara Erickson at the recent AngularConnect.

Did you learn something new? If so, please click the clap 👏 button below ⬇️ so more people can see this!

frontend.coach

Tutorials, news and tips & tricks from the front-end world

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store