Difference Between @Host and @Self Resolution Modifiers

Sinan Öztürk
4 min readMar 11, 2024

--

You probably came here for a reason, you read the doc and you didn’t understand the difference between @Self and @Host resolution modifiers.

I have experienced the same thing. I have read the documentation and they look the same.

I hope i will clarify these concepts. Let’s begin with @Self which is the simplest one.

@Self

  • @Self decorator tells DI to look for a dependency only from itself, so it will not walk up the tree.

Example

import { Component } from '@angular/core';
import { ChildDirective } from './child.directive';
import { EmojiService } from './emoji.service';

@Component({
selector: 'app-root',
standalone: true,
template: `
<p appChild>app component</p>
`,
providers: [{provide: EmojiService, useValue: '🍒'}],
imports: [ChildDirective]
})
export class AppComponent {}

Child Directive

import { Directive, Self, Optional } from '@angular/core';
import { EmojiService } from './emoji.service';

@Directive({
selector: '[appChild]',
standalone: true,
providers: [{provide: EmojiService, useValue: '🍌'}],
})
export class ChildDirective {
constructor(@Optional() @Self() public emoji: EmojiService) {
console.log(emoji);
}
}
  • We have used the @Self decorator so we got the 🍌 emoji. If we didn’t provide anything in Child Directive we will get null because we used @Self.
  • Thats all for @Self decorator. It just check its own injector, whichs are in the providers array.

@Host

  • @Host resolution modifiers tells angular to host element is the last stop for searching for providers.
    - It means it wont look for providers array of host component.
  • Every angular component has its own Host-Element and it is represented by component’s selector.

Example

I want to explain the @Host with this example, i am going to create an two directives.

  • childDirective
  • parentDirective

Now i want to show you the component and directives codes one by one, so we will be able to examine it easly.

app.component.ts

import { Component } from '@angular/core';
import { ChildDirective } from './child.directive';
import { EmojiService } from './emoji.service';
import { ParentDirective } from './parent.directive';

@Component({
selector: 'app-root',
standalone: true,
imports: [ChildDirective, ParentDirective],
template: `
<div appParent>
<p appChild>child component</p>
</div>
`,
providers: [{ provide: EmojiService, useValue: '🍒' }],
})
export class AppComponent { }

parent-directive.ts

import { Directive, Host, Optional } from '@angular/core';
import { EmojiService } from './emoji.service';

@Directive({
selector: '[appParent]',
standalone: true,
providers: [{ provide: EmojiService, useValue: '🍉' }],
})
export class ParentDirective {
constructor(@Optional() @Host() public emoji: EmojiService) {
console.log(emoji);
}
}

child-directive.ts

import { Directive, Host, Optional } from '@angular/core';
import { EmojiService } from './emoji.service';

@Directive({
selector: '[appChild]',
standalone: true,
providers: [{ provide: EmojiService, useValue: '🍌' }],
})
export class ChildDirective {
constructor(@Optional() @Host() public emoji: EmojiService) {
console.log(emoji);
}
}

Now lets play with child and parent directives.

  • Child Directive will be first check its own providers. So child directive will log 🍌 emoji.
  • Parent Directive will be first check its own providers. So child directive will log 🍉 emoji.
  • So we can say that @Host() will check its own provider list first.

If i remove providers array from child directive, it will get the provider from Parent Directive, which is 🍉 emoji.

Now i am removing the providers array from both directives, only the app.component has a provider. providers: [{ provide: EmojiService, useValue: '🍒' }].

See the result;

They both null because @Host resolution modifier doesn’t check host element, which is app component.

Is there a way to provide something from App Component to Directives while using the @Host resolution modifier in Directives?

import { Component } from '@angular/core';
import { ChildDirective } from './child.directive';
import { EmojiService } from './emoji.service';
import { ParentDirective } from './parent.directive';

@Component({
selector: 'app-root',
standalone: true,
imports: [ChildDirective, ParentDirective],
template: `
<div appParent>
<p appChild>child component</p>
</div>
`,
viewProviders: [{ provide: EmojiService, useValue: '🍒' }],
})
export class AppComponent { }

Result;

You might ask why is it important? It is important to understand this line of code:

You can read this article of mine to see real case example of usage https://medium.com/@sinanozturk/reusable-reactive-forms-components-a06fc0960818

--

--