angular
April 12

Передача инжектора во вложенные шаблоны

Начиная с Angular 14 инжектор можно передавать для при использовании вложенных шаблонов. В прошлом это было возможно только с помощью директивы ngComponentOutlet или API createComponent.

Давайте посмотрим, как это можно сделать:

Передача контекста

Когда шаблон передаётся компоненту, контекст инжектора для него и его дочерних элементов исходит из места объявления шаблона, а не из того места, где он был создан. Это поведение при необходимости можно изменить.

<app-foo [tpl]="tpl"></app-foo>

<ng-template #tpl>
  <app-bar></app-bar>
</ng-template>
@Component({
  selector: 'app-bar',
  template: `{{ name }}`
})
export class BarComponent {
  constructor(@Inject('name') public name: string) {}
}
@Component({
  selector: 'app-foo',
  template: `
    <ng-template [ngTemplateOutlet]="tpl" 
                 [ngTemplateOutletInjector]="injector">
    </ng-template>
  `
  providers: [{ provide: 'name', 'User' }]
})
export class FooComponent {
  @Input() tpl: TemplateRef<any>;

  constructor(public injector: Injector) { }
}

Создаётся новый провайдер в инжекторе компонента и передаётся инжектор ngTemplateOutletInjector. Теперь BarComponent будет использовать name, из инжектора FooComponent.

Обратите внимание, что новый инжектор действует как узловой инжектор, а не как инжектор модуля.

ViewContainer

<ng-container *appBaz>
  <app-bar></app-bar>
</ng-container>
@Component({
  selector: 'app-bar',
  template: `{{ name }}`
})
export class BarComponent {
  constructor(@Inject('🎁') public name: string) {
  }
}
@Directive({
  selector: '[appBaz]'
})
export class BazDirective {

  constructor(private vcr: ViewContainerRef, private tpl: TemplateRef<any>) {
  }

  ngOnInit() {
    this.vcr.createEmbeddedView(this.tpl, {}, {
      injector: Injector.create({
        providers: [{ provide: '🎁', useValue: '😝' }]
      })
    })
  }

}

Метод createEmbeddedView() теперь принимает инжектор как третий аргумент.