[Перевод] Angular: неочевидные возможности селекторов директив

Если вы когда-нибудь создавали директивы Angular, то вы, вероятно, использовали в качестве селектора конструкцию, в которой используются скобки: ([]). Такой подход, хотя чаще всего применяется именно он, не является единственно возможным. На самом деле, селекторы, используемые в директивах, дают программисту широкий простор для творчества. Для того чтобы продемонстрировать эту идею в действии, в материале, перевод которого мы публикуем сегодня, рассмотрена методика создания директивы, предназначенной для работы с внешними ссылками, которые имеются в шаблоне. В частности, речь пойдёт о том, как можно находить обычные HTML-элементы, и, при необходимости, исключать из выборки некоторые из них, используя псевдокласс :not.

59f9c24cee02cfd1f7028e39e4a6547a.png


Директива ngForm


Для того чтобы рассмотреть пример сложного селектора, взглянем на директиву ngForm:

@Directive({
  selector: 'form:not([ngNoForm]):not([formGroup]),ngForm,ng-form,[ngForm]',
})


Тут стоит обратить внимание на следующее:

  • Директива может быть рассчитана на несколько селекторов, которые можно перечислять через запятую.
  • Здесь можно смешивать целевые HTML-элементы (наподобие
    ) c HTML-атрибутами (вроде ngForm).
  • Для исключения каких-то элементов из выборки можно использовать псевдокласс :not.


Создание директивы для работы с внешними ссылками


Под внешней ссылкой мы понимаем тег , у которого нет директивы routerLink. Учитывая то, что мы выяснили, анализируя предыдущий пример, соответствующий селектор можно описать так:

@Directive({
  selector: 'a:not([routerLink])',
})


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

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

Результаты применения директивы к внешним ссылкам должны выглядеть так:

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


Обе эти цели достижимы благодаря использованию @HostBinding():

@Directive({
  selector: 'a:not([routerLink])'
})
export class ExternalLinkDirective {
  @HostBinding('rel')
  @Input()
  rel = 'noopener';

  @HostBinding('target')
  @Input()
  target = '_blank';
}


Обратите внимание на то, что тут мы, кроме прочего, декорировали свойства с помощью декоратора @Input(), что, при необходимости, открывает возможности для переопределения.

Ещё одна допустимая реализация подобного решения может заключаться в использовании декоратора @Attribute(). Такой подход даст небольшое увеличение в производительности, так как, в отличие от декоратора @Input(), при использовании @Attribute() значения соответствующих свойств вычисляются лишь один раз, то есть, не производится постоянной проверки свойств rel и target в цикле проверки изменений.

Подробности об этой методике можно почитать здесь.

Тестирование директивы


Создадим простой навигационный блок, содержащий ссылки, ведущие на внешние ресурсы:



Если, с помощью инструментов разработчика Chrome, посмотреть соответствующий HTML-код, то можно будет увидеть следующее:

9fa7b4023e47ace0b69359c39daafa51.png


HTML-код навигационного блока после применения директивы

Это именно то, что нам нужно. Директива работает без необходимости применения дополнительных селекторов атрибутов.

Итоги


Из этого материала вы узнали о том, что, при работе с директивами Angular, необязательно использовать селекторы атрибутов. Здесь мы сначала исследовали директиву ngForm, после чего использовали полученные знания для создания собственной директивы, предназначенной для работы с внешними ссылками. Надеемся, эта методика вам пригодится.

Уважаемые читатели! Если вам известны какие-нибудь неочевидные приёмы разработки веб-проектов с использованием Angular — просим о них рассказать.

1ba550d25e8846ce8805de564da6aa63.png

© Habrahabr.ru