Директивы
Директива — это компонент без view.
- Директиву можно размещать на теге, компоненте или шаблоне.
- В конструкторе директивы можно получить доступ соответственно к элементу, компоненту или темплейту, на который повешена директива.
- В параметре декоратора директивы можно ограничить элементы, к которым применима директива (по тегу или названию компонента). С другими элементами директива не отработает.
- Если мы не уверены, что директива будет навешена компонент или темплейт, то указываем в конструкторе декоратор @Optional
Универсальная директива (можно повесить на любой тег или компонент):
import { Directive, ElementRef } from '@angular/core'; @Directive({ selector: '[appMyDirective]' }) export class MyDirectiveDirective { constructor(private el: ElementRef) { console.log(el); // html element } }
Ограничение использование директивы по селектору тега
Например, создадим директиву, которую можно вешать только на ссылки (т.е. на тег «a»):
import { Directive, ElementRef } from '@angular/core'; @Directive({ selector: 'a[appMyDirective]' //указываем, что только для тега "a" }) export class MyDirectiveDirective { constructor(private el: ElementRef<HTMLLinkElement>) { // мы точно знаем, что теперь может быть только ссылка console.log(el); // html element } }
В html коде будет ошибка, что этот атрибут (директива) неизвестен или неразрешен здесь, если попытаться повесить ее на другой тег.
Но у меня VSCode не показал ошибку и приложение сбилдилось без проблем, но сама директива не отработала.
Аналогичным образом можно создать директиву, которая будет работать только с конкретным компонентом. Более того, так как мы знаем, что директива будет работать только с конкретным компонентом, то можно попросить доступ к этому компоненту (в конструкторе):
import { Directive, ElementRef } from '@angular/core'; import { MyComponentComponent } from './components/my-component/my-component.component'; @Directive({ selector: 'app-my-component[appMyDirective]' //указываем, что только для этого компонента }) export class MyDirectiveDirective { constructor(private el: ElementRef<HTMLLinkElement>, private component: MyComponentComponent // можем обращаться к компоненту, // так как директива применима только к нему ) { console.log(el, component); } }
Опциональный запрос компонента в конструкторе директивы (декоратор @Optional)
В предыдущем примере мы точно знали, что компонент будет доступен, так как ограничили применение директивы по тегу.
Но если это универсальная директива, и она может быть навешена не только на конкретный компонент, то для обращения к компоненту (если он доступен) нужно использовать на параметре в конструкторе декоратор @Optional. Это поможет избежать ошибки при попытке на весить директиву на что-то другое.
import { Directive, ElementRef, Optional } from '@angular/core'; import { MyComponentComponent } from './components/my-component/my-component.component'; @Directive({ selector: '[appMyDirective]' }) export class MyDirectiveDirective { constructor(private el: ElementRef<HTMLLinkElement>, @Optional() private component: MyComponentComponent // благодаря декоратору, если это не тот компонент, // то значение будет просто null, а не ошибка ) { console.log(el, component); } }
Применение директивы к шаблону
По аналогии с предыдущим примером, можно применить директиву и к шаблону:
import { Directive, Optional, TemplateRef } from '@angular/core'; @Directive({ selector: '[appMyDirective]' }) export class MyDirectiveDirective { constructor( @Optional() private template: TemplateRef<any> //получаем темплейт, если директива навешена на него ) { console.log(template); //доступ к темплейту <ng-template></ng-template> } }
Эта директива может теперь взять и отрисовать этот шаблон. Но это уже тема о структурных директивах.