Использование директивы несколько раз для элемента

Объяснение того, как Angular обрабатывает элементы, для которых директива создается более одного раза

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

В этой статье я собираюсь объяснить сценарий, в котором директива используется более одного раза в элементе, и как Angular обрабатывает такие случаи.

Как обычно, давайте рассмотрим простой пример. Я собираюсь создать директиву square, которая обновляет значение хост-элемента до квадрата его значения. Вот простая реализация этой директивы:

И чтобы использовать это в элементе ввода, вот пример кода, который выглядит так:

Итак, мы устанавливаем значение 10 для ввода, но во время инициализации вызывается директива appSquare и обновляет значение при вводе до квадрата его значения, 100.

Вот как выглядит ввод после рендеринга:

Теперь, например, если мы хотим возвести в квадрат возведенное в квадрат значение, например, если мы передаем 10, тогда входные данные должны быть обновлены с помощью 10000 Итак, можем ли мы использовать appSqauredirective дважды для этого элемента, чтобы достичь этого?

Давайте разберемся в этом сейчас, обновив приведенный выше пример.

После обновления ввода шаблон теперь выглядит так:

И результат, отображаемый в пользовательском интерфейсе, выглядит следующим образом:

Да, значение осталось прежним.

Что здесь происходит?

Давайте сделаем шаг назад и поймем, как работает процесс компиляции Angular, когда директива добавляется к элементу более одного раза.

Во время процесса компиляции Angular компилятор Angular выполняет определение каждого элемента и устанавливает атрибуты для нативного элемента. И реализация этой части показана ниже.

Исходный код: https://github.com/angular/angular/blob/master/packages/platform-browser/src/dom/dom_renderer.ts#L184

Поскольку атрибуты установлены как Map в собственном элементе, невозможно определить один и тот же атрибут более одного раза (поскольку ключи уникальны в Map, если они являются литералами, и в этом случае они сравниваются по значению).

Поскольку Angular выполняет цикл по всем атрибутам, определенным для элемента, в порядке их размещения, сохраняется самый последний атрибут типа в элементе.

Давайте изменим предыдущий пример директивы, чтобы он принимал входное значение и передавал разные значения для каждого экземпляра директивы. В этом случае приоритет будет отдан последней директиве.

А теперь давайте обновим шаблон, чтобы передать значения для обоих экземпляров директивы. Поскольку у нас есть @Input, определенный с тем же именем, что и селектор директив, нам не нужно передавать дополнительные входные данные, и вместо этого мы можем просто передать значение декларации directive самостоятельно (он выполняет обе обязанности как селектор директивы и декоратор ввода).

Вот как это выглядит:

Если мы сейчас запустим наше приложение, то увидим это в консоли:

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

Вот и все. Спасибо за прочтение! Следуйте за мной на Medium, чтобы увидеть больше интересных статей.