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]