Как передать экземпляр директивы атрибута во вложенный компонент с помощью внедрения зависимостей в Angular

Я пытаюсь использовать атрибут Directive для передачи ссылки на шаблон элемента из родительского компонента во вложенный компонент с помощью внедрения зависимостей, но экземпляр Directive в родительском компоненте, который удерживает целевой элемент, не является тем же экземпляром, что и внедряется во вложенный компонент - создается второй экземпляр Директивы, который не имеет доступа к целевому элементу, и это тот, который внедряется.

Это основная структура:

<div>
  <div #myTarget [appendTarget]="myTarget"></div>
  <child>
    <grandchild></grandchild>
  </child>
</div>

Я пытаюсь передать ссылку на #myTarget до <grandchild>, используя Директиву appendTarget и DI, а не @Inputs (что отлично работает), поэтому <child> не нужно знать об этом и действовать как сквозной.

Я включил AppendTargetDirective в массив providers родительского компонента:

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  providers: [
    AppendTargetDirective
  ]
})
export class AppComponent {
  constructor() { }
}

и вставил его в компонент <grandchild>:

@Component({
  selector: 'grandchild',
  template: `
<div>
  Hi! Grandchild here...
</div>
  `
})
export class GrandchildComponent  {
  constructor(
    private appendTargetDirective: AppendTargetDirective
  ) {}
}

Однако создаются два экземпляра AppendTargetDirective: один захватывает ссылку на #myTarget, другой нет, а GrandchildComponent получает последнюю.

Вот StackBlitz демонстрация проблемы. Если вы откроете консоль, вы увидите, что конструктор Directive вызывается дважды (я генерирую уникальный идентификатор для каждого экземпляра в его конструкторе), и что экземпляр, который удерживает целевой элемент, не является экземпляром, который вводится . Я думал, что включение его в массив providers родительского компонента приведет к созданию его единственного экземпляра, который будет использоваться родительским компонентом и его потомками, но, очевидно, я неправильно думаю.

Любая помощь будет принята с благодарностью.




Ответы (1)


Вы НИКОГДА не должны добавлять директивы Angular в массив providers. Angular будет рассматривать их как службы, которые являются отдельными экземплярами классов директив и вообще не привязаны к структуре шаблона.

Вот как Angular пытается разрешить зависимость директив в вашем случае.

Он начинается с текущего элемента и идет вверх по дереву

  3 ^  <div>
        <div #myTarget [appendTarget]="myTarget"></div>
  2 ^     <child>   
  1 ^       <grandchild></grandchild>
          </child>
       </div>

DI для директив будет работать, если вы поместите директиву в ту же ветку HTML-дерева, где находится ваш ребенок:

<div>
  <div #myTarget></div>
  <child [appendTarget]="myTarget">   <--------------------------- move it here
    <grandchild></grandchild>
  </child>
</div>

Раздвоенный Stackblitz

person yurzui    schedule 25.07.2020