Где живет пользовательский экземпляр канала? Как код компонента может получить доступ к экземпляру пользовательского канала, используемому в его HTML?

У меня есть пользовательский канал, который я использую в части HTML компонента. В модуле объявлено:

  declarations: [  I18nPipe ],

Я хочу иметь возможность вызывать метод из кода компонента (не transform метод).

Я надеялся, что экземпляр канала живет где-то в контексте внедрения зависимостей, чтобы я мог получить его. Но я был неправ. Если я вставлю его в конструктор компонента (например, в любой обычный сервис):

  constructor(private i18nPipe: I18nPipe)  

тогда я получил ошибку: нет поставщиков. Поэтому я включаю его в providers раздел того же модуля:

  providers: [ I18nPipe ]

тогда у меня будет доступ к нему в коде компонента, но будет два экземпляра моего пользовательского канала.

  1. создано providers, доступно в контексте DI. Я получу этот экземпляр при внедрении в конструктор, поэтому я буду работать с этим экземпляром в коде моего компонента.

  2. экземпляр, который используется в HTML. Где оно живет? Я хочу получить доступ к этому экземпляру в коде моего компонента, а не к "предоставленному"; как я могу получить это?

1 ответ

Решение

Каждый угловой компонент компилируется в представление с узлами. И трубы являются одним из типов узлов. И вы не можете внедрить узлы вида, кроме родительских компонентов и директив, определенных в элементе host компонента.

Предположим, у вас есть следующий шаблон для компонента:

<div>{{3|mypipe}}</div>

У вас будут следующие узлы просмотра:

PipeElement
HTMLDivElement
HTMLTextElement

Затем во время обнаружения изменений Angular проходит через каждый узел и выполняет определенное действие по обнаружению изменений - обновление dom, обновление привязок или transform вызов метода.

Если вы хотите, вы можете получить доступ к экземпляру канала через экземпляр View (который не является публичным API) следующим образом:

class I18nPipe {
   sayHello() {}
}

class ComponentWithPipe {

  constructor(cd: ChangeDetectorRef) {
    setTimeout(() => {
      const pipeNode = cd._view.nodes.find((n) => {
        return n.instance && n.instance instanceof I18nPipe
      });
      const pipeInstance = pipeNode.instance;
      pipeInstance.sayHello();
    })
  }

Но это только для образовательных целей. Вы не хотите использовать этот подход в производстве.

Вот несколько статей, которые помогут вам понять:

Другие вопросы по тегам