Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the difference between @Host and @Self in angular? [duplicate]

Tags:

angular

In the Angular docs, I found the following passage:

Specifies that an Injector should retrieve a dependency only from itself.

Specifies that an injector should retrieve a dependency from any injector until reaching the host element of the current component.

What is the meaning of 'host element'?

like image 412
zk922 Avatar asked Oct 24 '25 19:10

zk922


1 Answers

Host Elements:

The concept of a host element applies to both directives and components.

For a directive, the concept is fairly straight forward. Whichever template tag you place your directive attribute on is considered the host element.

If we were implementing the HighlightDirective above like so:

<div>
  <p appHighlight>
    <span>Text to be highlighted</span>
  </p>
</div>

The <p> tag would be considered the host element. If we were using a custom TextBoxComponent as the host, the code would look like this:

<div>
  <app-my-text-box appHighlight>
    <span>Text to be highlighted</span>
  </app-my-text-box>
</div>

n the context of a Component, the host element is the tag that you create through the selector string in the component configuration. For the TextBoxComponent in the example above, the host element in the context of the component class would be the tag.

@Self:

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

Angular will only look for a value that is bound on the component injector for the element that this Directive/Component exists on.

class Dependency {}

@Injectable()
class NeedsDependency {
  constructor(@Self() public dependency: Dependency) {}
}

let inj = ReflectiveInjector.resolveAndCreate([Dependency, NeedsDependency]);
const nd = inj.get(NeedsDependency);

expect(nd.dependency instanceof Dependency).toBe(true);

inj = ReflectiveInjector.resolveAndCreate([Dependency]);
const child = inj.resolveAndCreateChild([NeedsDependency]);
expect(() => child.get(NeedsDependency)).toThrowError();

@Host:

The @Host decorator tells DI to look for a dependency in any injector until it reaches the host

Angular will look for a value that is bound on either the component injector for the element that this Directive/Component exists on, or on the injector of the parent component. Angular calls this parent component the "host".

class OtherService {}
class HostService {}

@Directive({selector: 'child-directive'})
class ChildDirective {
  logs: string[] = [];

  constructor(@Optional() @Host() os: OtherService, @Optional() @Host() hs: HostService) {
    // os is null: true
    this.logs.push(`os is null: ${os === null}`);
    // hs is an instance of HostService: true
    this.logs.push(`hs is an instance of HostService: ${hs instanceof HostService}`);
  }
}

@Component({
  selector: 'parent-cmp',
  viewProviders: [HostService],
  template: '<child-directive></child-directive>',
})
class ParentCmp {
}

@Component({
  selector: 'app',
  viewProviders: [OtherService],
  template: '<parent-cmp></parent-cmp>',
})
class App {
}

Listening to an Element Host:

Listening to the host - that is, the DOM element the directive is attached to - is among the primary ways directives extend the component or element's behavior. Previously, we saw its common use case.

@Directive({
  selector: '[appMyDirective]'
})
class MyDirective {
  @HostListener('click', ['$event'])
  onClick() {}
}

We can also respond to external events, such as from window or document, by adding the target in the listener.

@Directive({
  selector: `[appHighlight]`
})
export class HighlightDirective {
  constructor(private el: ElementRef, private renderer: Renderer) { }

  @HostListener('document:click', ['$event'])
  handleClick(event: Event) {
    if (this.el.nativeElement.contains(event.target)) {
      this.highlight('yellow');
    } else {
      this.highlight(null);
    }
  }

  highlight(color) {
    this.renderer.setElementStyle(this.el.nativeElement, 'backgroundColor', color);
  }
}

Example:https://plnkr.co/edit/iJvMpPYDQmiwqvUTKSU8?p=preview