Перейти к содержанию

Создание атрибутивных директив

Атрибутивные директивы меняют поведение элемента, к которому они применяются. Например, директива ngClass позволяет установить для элемента класс CSS. При этом сама директива применяется к элементу в виде атрибута:

1
<div [ngClass]="{verdanaFont:true}"></div>

И при необходимости мы можем сами создавать какие-то свои директивы атрибутов для каких-то определенных целей. Итак, создадим свою директиву. Добавим в папку src/app новый файл, который назовем bold.directive.ts:

Структура приложения

Определим в файле bold.directive.ts следующий код:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import { Directive, ElementRef } from '@angular/core'

@Directive({
  selector: '[bold]',
})
export class BoldDirective {
  constructor(private elementRef: ElementRef) {
    this.elementRef.nativeElement.style.fontWeight = 'bold'
  }
}

Директива — это обычный класс на TS, к которому применяется декоратор @Directive, соответственно нам надо импортировать эту директиву из @angular/core. Кроме того, здесь импортируется класс ElementRef. Он представляет ссылку на элемент, к которому будет применяться директива.

При применении декоратора @Directive необходимо определить селектор CSS, с которым будет ассоциирована директива. Селектор CSS для атрибута должен определяться в квадратных скобках. В данном случае в качестве селектора выступает [bold].

Сам декоратор @Directive применяется к классу, который называется BoldDirective. Это собственно и есть класс директивы, который определяет ее логику.

Для получения элемента, к которому применяется данная директива, в классе определен конструктор, имеющий один параметр: private elementRef: ElementRef. Через этот параметр Angular будет передавать или инжектировать тот элемент из шаблона, в котором применяется директива.

Поскольку параметр определен с ключевым словом private, то для него будет создаваться одноименная приватная переменная, через которую мы можем получить объект ElementRef и произвести с ним какие-либо манипуляции. В частности, здесь идет обращение к вложенному свойству nativeElement, через которое у элемента устанавливается жирный шрифт:

1
this.elementRef.nativeElement.style.fontWeight = 'bold'

Теперь возьмем код главного компонента и применим директиву:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import { Component } from '@angular/core'

@Component({
  selector: 'my-app',
  template: `
    <div>
      <p bold>Hello Angular 2</p>
      <p>
        Angular 2 представляет модульную архитектуру
        приложения
      </p>
    </div>
  `,
})
export class AppComponent {}

Здесь определено два параграфа, и к первому из них применяется директива. Поскольку в коде директивы был определен селектор [bold], то чтобы ее применить, в коде элемента применяется данный селектор.

Но сама по себе директива не заработает. Нам еще надо ее подключить в модуле приложения — классе AppModule:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { AppComponent } from './app.component'
import { BoldDirective } from './bold.directive'

@NgModule({
  imports: [BrowserModule],
  declarations: [AppComponent, BoldDirective],
  bootstrap: [AppComponent],
})
export class AppModule {}

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

1
import { BoldDirective } from './bold.directive'

Затем она добавляется в секцию declarations:

1
declarations: [ AppComponent, BoldDirective],

И если мы запустим приложение, то увидим применение директивы к первому параграфу:

Структура приложения

Для управления стилизацией элемента выше этот элемента извлекался через объект ElementRef в конструкторе директивы, и у него устанавливались стилевые свойства. Однако гораздо удобнее для управления стилем использовать рендерер. Так, изменим директиву следующим образом:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import {
  Directive,
  ElementRef,
  Renderer2,
} from '@angular/core'

@Directive({
  selector: '[bold]',
})
export class BoldDirective {
  constructor(
    private elementRef: ElementRef,
    private renderer: Renderer2
  ) {
    this.renderer.setStyle(
      this.elementRef.nativeElement,
      'font-weight',
      'bold'
    )
  }
}

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

Комментарии