Dyrektywy i potoki - praktyczny przykład
Spróbujmy wykorzystać zdobytą wiedzę w praktyce. Portal czasopisma internetowego argumenty.net udostępnia API za pomocą którego można odczytać artykuły. Na przykład http://www.argumenty.net/jarg.php?/g/n/58 ściągnie najnowszy artykuł z kategorii 58. Ponieważ na razie nie zajmujemy się transmisją, zbudujmy moduł udostępniający odczytane treści w postaci listy (json.ts):
export class fromJson {
public boxes = [];
public cat58 =
{
catid:58,
art: {
id:"2580",
title:"Kredyty \u201efrankowe\u201d w wojnie hybrydowej",
content:"<p>......<\/p>"
}
};
public cat60 =
{
catid:60,
art: {
id:"1894",
title:"Optymistycznie o Grecji",
content:"<p>. ...<\/p>"
}
};
constructor() {
this.boxes.push(this.cat58);
this.boxes.push(this.cat60);
}
}
Teraz możemy stworzyć komponent wyświetlający ramki z artykułami:
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { fromJson } from './json';
@Component({
selector: 'dashboard',
template: `<div *ngFor="let box of json.boxes"
[class]="box.catid" [id]="box.art.id">
<h1>{{box.art.title}}</h1>
<div [innerHTML]="box.art.content">
</div>
</div>`
})
export class DashboardComponent {
json : fromJson;
constructor() {
this.json = new fromJson();
}
}
Zauważmy jak bez problemów - stosując notację kropkową - możemy w szablonach sięgać do wnętrza obiektów. Ponieważ ściągnięta z internetu treść artykułu jest zakodowana w HTML - nie możemy jej wpisać w szablon tak jak tytuł - gdyż znaczniki html zostaną przetworzone tak, aby były widoczne. Dlatego spinamy ją z własnością innerHTML znacznika div.
Aby wyświetlić artykuły - wystarczy wpisać w szablonie:
<dashboard></dashboard>
Dodajmy teraz filtr, który opakuje nam treść artykułu (wipe.pipes.ts):
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'wrap'
})
export class WrapContentPipe implements PipeTransform {
transform(text : string): string {
return '<div class="content">'+text+'</div>';
}
}
Możemy go zastosować (po zaimportowaniu do modułu):
<div [innerHTML]="box.art.content | wrap"></div>
Aby uzyskać większą swobodę w redagowaniu okienek z artykułami, stwórzmy jeszcze jeden komponent (box.component.ts):
import { Component, Input } from '@angular/core';
@Component({
selector: 'box',
template: `
<div class="box"
>
<div class="inner">
<div class="title">{{ title }}</div>
<ng-content></ng-content>
</div>
</div>
`,
styleUrls: ['./box.component.css']
})
export class BoxComponent {
@Input() catid : number;
@Input() id : number;
@Input() title : string;
}
Użycie ng-content
oznacza, że chcemy rzekazać treść artykułu jako projekcję. Natomiast tytuł i identyfikatory - poprzez zwykły Input()
.
Drobna zmiana w dashboard.component.ts
pozwoli na wykorzystanie nowo stworzonego komponentu:
template: `<box *ngFor="let box of json.boxes"
[catid]="box.catid" [id]="box.art.id"
[title]="box.art.title">
<div
[innerHTML]="box.art.content | wrap">
</div>
</box>
`
Na koniec dodajmy zmianę stylu - zależnie od tego, czy wyświetlany artykuł jest "topowy" (dodajmy wartość topnews do listy w json.ts). Zastosujmy w tym celu obiekt do użycia w dyrektywie ngStye o nazwie boxStyle. Jego ustawienie możemy zmieniać w zdarzeniu ngOnChanges należącym do cyklu życia komponentu. Wymaga to zastosowania interfejsu OnChanges.
import { Component, Input, OnChanges } from '@angular/core';
@Component({
selector: 'box',
template: `
<div class="box"
[ngStyle]=boxStyle
>
<div class="inner">
<div class="title">{{ title }}</div>
<ng-content></ng-content>
</div>
</div>
`,
styleUrls: ['./box.component.css']
})
export class BoxComponent implements OnChanges{
@Input() catid : number;
@Input() id : number;
@Input() title : string;
@Input() topnews : number;
public boxStyle = { };
ngOnChanges() {
if (this.topnews)
this.boxStyle= { 'color' : 'blue'}
else this.boxStyle = { };
}
}
Zobacz pełny przykład: [arg0]