Директивы

Директива – это компонент без view.

  1. Директиву можно размещать на теге, компоненте или шаблоне.
  2. В конструкторе директивы можно получить доступ соответственно к элементу, компоненту или темплейту, на который повешена директива.
  3. В параметре декоратора директивы можно ограничить элементы, к которым применима директива (по тегу или названию компонента). С другими элементами директива не отработает.
  4. Если мы не уверены, что директива будет навешена компонент или темплейт, то указываем в конструкторе декоратор @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>
  }
}

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *