Dyrektywy
Angular
ma trzy rodzaje dyrektyw:
komponenty - dyrektywy z szablonem,
dyrektywy strukturalne - zmieniają układ
DOM
-u dodając oraz usuwając jego elementy, na przykład*ngFor
,*ngIf
,dyrektywy atrybutu - zmieniają wygląd oraz zachowanie elementów
DOM
, komponentów czy też innych dyrektyw.
Dyrektywy atrybutu
Dyrektywa atrybutu (ang. attribute directive) pozwala uzyskać dostęp do natywnego elementu DOM
-u i dokonać jego modyfikacji.
Najpopularniejszą dyrektywą atrybytu jest ngStyle
, która służy do manipulacji stylami elementu.
<div [ngStyle]="{'style-name': styleValue}">
<!-- ... -->
</div>
podstawy
Dyrektywy podobnie jak komponenty mają swoje selektory. Definiujemy je podając metadane do dekoratora @Directive
.
Ważnym szczegółem jest konieczność otoczenia nazwy dyrektywy kwadratowymi nawiasami []
aby mógł on być używany jako atrybut.
@Directive({
selector: '[appAutoFocus]'
})
export class AutoFocusDirective {}
Dostęp do elementu uzyskujemy w konstruktorze, który jako parametr otrzymuje obiekty typu ElementRef
.
@Directive({
selector: '[appAutoFocus]'
})
export class AutoFocusDirective {
constructor(element: ElementRef) {
//...
}
}
cykl życia
W dyrektywie podobnie jak w komponencie możemy skorzystać z uchwytów do jego cyklu życia. Aby to zrobić poprostu je implementujemy.
@Directive({
selector: '[appAutoFocus]'
})
export class AutoFocusDirective implements AfterViewInit {
constructor(element: ElementRef) {
//...
}
ngAfrterViewInit () {
//...
}
}
dodatkowe parametry
Mamy również możliwość definiowania dodatkowych parametrów dyrektyw. Ponownie, podobnie jak w komponentach, korzystamy z @Input
.
@Directive({
selector: '[appAutoFocus]'
})
export class AutoFocusDirective implements AfterViewInit {
@Input('appAutoFocusActive') isActive: boolean;
constructor(element: ElementRef) {
//...
}
ngAfrterViewInit () {
//...
}
}
wykorzystanie
Aby wykorzystać naszą dyrektywę umieszczamy ją w wybranym elemencie szablonu.
<md-input-container>
<input mdInput
[(ngModel)]="searchPhrase"
[disabled]="!isActive"
appAutoFocus
[appAutoFocusActive]="isActive"
type="text"
placeholder="Search..."
>
</md-input-container>
- - -
Zbudujemy swoją dyrektywę, która będzie ustawiała focus
na naszą wyszukiwarkę piw kiedy stanie się ona aktywna.
Przykłady: beers-search.component.html, auto-focus.directive.ts v28
Dyrektywy strukturalne
Dyrektywy strukturalne (ang. structural directive) służą do manipulowania układem elementów widoku. Zazwyczaj poprzez dodawanie, usuwanie oraz modyfikowanie elementów DOM
.
Najpopularniejszymi przykładami są *ngIf
oraz *ngFor
.
przedrostek *
Dyrektywę strukturalną łatwo rozpoznać dzięki przedrostkowi *
. Nie jest to jednak jedynie konwencja ale uproszczona notacja, którą Angular
tłumaczy na element <ng-template>
.
*ngIf
Aby zobaczyć co dzieje się pod maską przyjrzymy się bliżej dyrektywie *ngIf
.
<div *ngIf="condition">
<!-- ... -->
</div>
Gdy kompilator widzi taki zapis zamienia go na atrybut tempate
.
<div template="ngIf condition">
<!-- ... -->
</div>
Kolejnym krokiem jest zamiana na <ng-tempalte>
z prostym przypisaniem atrybutu [ngIf]
.
<ng-template [ngIf]="conditin">
<div>
<!-- ... -->
</div>
</ng-template>
W tym momencie *ngIf
ma już proste zadanie i działa dokładnie tak jak dyrektywa atrybutu, która umieszcza bądź usuwa swoją zawartość w elemencie <ng-tempalte>
.
Aby móc dokonać tej manipulacji potrzebujemy dostp do elementów reprezentujących:
- zawartość
<ng-template>
-TemplateRef
, - miejsce, w którym został on zdefiniowany -
ViewContainerRef
.
Implementacja *ngIf
może wyglądać następująco:
@Directive({
selector: '[ngIf]'
})
export class NgIfDirective {
@Input() set ngIf (condition: boolean) {
if (condition) {
this.viewContainer.createEmbeddedView(this.templateRef);
} else {
this.viewContainer.clear();
}
}
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef
) {}
}