Angular 2
Interazioni componenti
Ricerca…
Sintassi
-
<element [variableName]="value"></element> //Declaring input to child when using @Input() method.
-
<element (childOutput)="parentFunction($event)"></element> //Declaring output from child when using @Output() method.
-
@Output() pageNumberClicked = new EventEmitter(); //Used for sending output data from child component when using @Output() method.
-
this.pageNumberClicked.emit(pageNum); //Used to trigger data output from child component. when using @Output() method.
-
@ViewChild(ComponentClass) //Property decorator is required when using ViewChild.
Parametri
Nome | Valore |
---|---|
pageCount | Utilizzato per indicare il numero di pagine da creare nel componente figlio. |
pageNumberClicked | Nome della variabile di output nel componente figlio. |
pageChanged | Funzione al componente padre che ascolta i componenti figlio in uscita. |
Interazione padre-figlio con proprietà @Input e @Output
Abbiamo un componente DataList che mostra i dati estratti da un servizio. DataListComponent ha anche un PagerComponent dato che è figlio.
PagerComponent crea l'elenco dei numeri di pagina in base al numero totale di pagine ricevute da DataListComponent. PagerComponent consente inoltre a DataListComponent di sapere quando l'utente fa clic su qualsiasi numero di pagina tramite la proprietà Output.
import { Component, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DataListService } from './dataList.service';
import { PagerComponent } from './pager.component';
@Component({
selector: 'datalist',
template: `
<table>
<tr *ngFor="let person of personsData">
<td>{{person.name}}</td>
<td>{{person.surname}}</td>
</tr>
</table>
<pager [pageCount]="pageCount" (pageNumberClicked)="pageChanged($event)"></pager>
`
})
export class DataListComponent {
private personsData = null;
private pageCount: number;
constructor(private dataListService: DataListService) {
var response = this.dataListService.getData(1); //Request first page from the service
this.personsData = response.persons;
this.pageCount = response.totalCount / 10;//We will show 10 records per page.
}
pageChanged(pageNumber: number){
var response = this.dataListService.getData(pageNumber); //Request data from the service with new page number
this.personsData = response.persons;
}
}
@NgModule({
imports: [CommonModule],
exports: [],
declarations: [DataListComponent, PagerComponent],
providers: [DataListService],
})
export class DataListModule { }
PagerComponent elenca tutti i numeri di pagina. Impostiamo l'evento click su ognuno di essi in modo che possiamo far sapere al genitore il numero di pagina cliccato.
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'pager',
template: `
<div id="pager-wrapper">
<span *ngFor="#page of pageCount" (click)="pageClicked(page)">{{page}}</span>
</div>
`
})
export class PagerComponent {
@Input() pageCount: number;
@Output() pageNumberClicked = new EventEmitter();
constructor() { }
pageClicked(pageNum){
this.pageNumberClicked.emit(pageNum); //Send clicked page number as output
}
}
Parent - Interazione bambino usando ViewChild
Viewchild offre un'interazione unidirezionale da genitore a figlio. Non vi è alcun feedback o output da parte del bambino quando viene utilizzato ViewChild.
Abbiamo un componente DataList che mostra alcune informazioni. DataListComponent ha PagerComponent come figlio. Quando l'utente effettua una ricerca su DataListComponent, ottiene un dato da un servizio e chiede a PagerComponent di aggiornare il layout di paging in base al nuovo numero di pagine.
import { Component, NgModule, ViewChild } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DataListService } from './dataList.service';
import { PagerComponent } from './pager.component';
@Component({
selector: 'datalist',
template: `<input type='text' [(ngModel)]="searchText" />
<button (click)="getData()">Search</button>
<table>
<tr *ngFor="let person of personsData">
<td>{{person.name}}</td>
<td>{{person.surname}}</td>
</tr>
</table>
<pager></pager>
`
})
export class DataListComponent {
private personsData = null;
private searchText: string;
@ViewChild(PagerComponent)
private pagerComponent: PagerComponent;
constructor(private dataListService: DataListService) {}
getData(){
var response = this.dataListService.getData(this.searchText);
this.personsData = response.data;
this.pagerComponent.setPaging(this.personsData / 10); //Show 10 records per page
}
}
@NgModule({
imports: [CommonModule],
exports: [],
declarations: [DataListComponent, PagerComponent],
providers: [DataListService],
})
export class DataListModule { }
In questo modo è possibile chiamare le funzioni definite sui componenti figlio.
Il componente figlio non è disponibile fino al rendering del componente principale. Si tenta di accedere al bambino prima che i genitori AfterViewInit
gancio cyle vita causerà un'eccezione.
Interazione genitore-figlio bidirezionale attraverso un servizio
Servizio utilizzato per la comunicazione:
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class ComponentCommunicationService {
private componentChangeSource = new Subject();
private newDateCreationSource = new Subject<Date>();
componentChanged$ = this.componentChangeSource.asObservable();
dateCreated$ = this.newDateCreationSource.asObservable();
refresh() {
this.componentChangeSource.next();
}
broadcastDate(date: Date) {
this.newDateCreationSource.next(date);
}
}
Componente genitore:
import { Component, Inject } from '@angular/core';
import { ComponentCommunicationService } from './component-refresh.service';
@Component({
selector: 'parent',
template: `
<button (click)="refreshSubsribed()">Refresh</button>
<h1>Last date from child received: {{lastDate}}</h1>
<child-component></child-component>
`
})
export class ParentComponent implements OnInit {
lastDate: Date;
constructor(private communicationService: ComponentCommunicationService) { }
ngOnInit() {
this.communicationService.dateCreated$.subscribe(newDate => {
this.lastDate = newDate;
});
}
refreshSubsribed() {
this.communicationService.refresh();
}
}
Componente figlio:
import { Component, OnInit, Inject } from '@angular/core';
import { ComponentCommunicationService } from './component-refresh.service';
@Component({
selector: 'child-component',
template: `
<h1>Last refresh from parent: {{lastRefreshed}}</h1>
<button (click)="sendNewDate()">Send new date</button>
`
})
export class ChildComponent implements OnInit {
lastRefreshed: Date;
constructor(private communicationService: ComponentCommunicationService) { }
ngOnInit() {
this.communicationService.componentChanged$.subscribe(event => {
this.onRefresh();
});
}
sendNewDate() {
this.communicationService.broadcastDate(new Date());
}
onRefresh() {
this.lastRefreshed = new Date();
}
}
AppModule:
@NgModule({
declarations: [
ParentComponent,
ChildComponent
],
providers: [ComponentCommunicationService],
bootstrap: [AppComponent] // not included in the example
})
export class AppModule {}