Difference Between @Host and @Self Resolution Modifiers
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?
- Yes, you can do that with
viewProviders
. - Modify the app component as below.
- You can check my article about viewProviders.
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