Innanzitutto, ciò di cui hai bisogno per capire le relazioni tra i componenti. Quindi puoi scegliere il giusto metodo di comunicazione. Proverò a spiegare tutti i metodi che conosco e utilizzo nella mia pratica per la comunicazione tra i componenti.
Quali tipi di relazioni tra i componenti possono esserci?
1. Genitore> Figlio
Condivisione dei dati tramite input
Questo è probabilmente il metodo più comune di condivisione dei dati. Funziona utilizzando il @Input()
decoratore per consentire il passaggio dei dati tramite il modello.
parent.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'parent-component',
template: `
<child-component [childProperty]="parentProperty"></child-component>
`,
styleUrls: ['./parent.component.css']
})
export class ParentComponent{
parentProperty = "I come from parent"
constructor() { }
}
child.component.ts
import { Component, Input } from '@angular/core';
@Component({
selector: 'child-component',
template: `
Hi {{ childProperty }}
`,
styleUrls: ['./child.component.css']
})
export class ChildComponent {
@Input() childProperty: string;
constructor() { }
}
Questo è un metodo molto semplice. È facile da usare. Possiamo anche rilevare le modifiche ai dati nel componente figlio utilizzando ngOnChanges .
Ma non dimenticare che se usiamo un oggetto come dati e cambiamo i parametri di questo oggetto, il riferimento ad esso non cambierà. Pertanto, se vogliamo ricevere un oggetto modificato in un componente figlio, deve essere immutabile.
2. Figlio> Genitore
Condivisione dei dati tramite ViewChild
ViewChild consente di iniettare un componente in un altro, dando al genitore l'accesso ai suoi attributi e funzioni. Un avvertimento, tuttavia, è che child
non sarà disponibile fino a dopo l'inizializzazione della vista. Ciò significa che è necessario implementare l'hook del ciclo di vita AfterViewInit per ricevere i dati dal figlio.
parent.component.ts
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from "../child/child.component";
@Component({
selector: 'parent-component',
template: `
Message: {{ message }}
<child-compnent></child-compnent>
`,
styleUrls: ['./parent.component.css']
})
export class ParentComponent implements AfterViewInit {
@ViewChild(ChildComponent) child;
constructor() { }
message:string;
ngAfterViewInit() {
this.message = this.child.message
}
}
child.component.ts
import { Component} from '@angular/core';
@Component({
selector: 'child-component',
template: `
`,
styleUrls: ['./child.component.css']
})
export class ChildComponent {
message = 'Hello!';
constructor() { }
}
Condivisione dei dati tramite Output () ed EventEmitter
Un altro modo per condividere i dati è quello di emettere dati dal figlio, che possono essere elencati dal genitore. Questo approccio è ideale quando si desidera condividere le modifiche ai dati che si verificano su clic sui pulsanti, voci di modulo e altri eventi utente.
parent.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'parent-component',
template: `
Message: {{message}}
<child-component (messageEvent)="receiveMessage($event)"></child-component>
`,
styleUrls: ['./parent.component.css']
})
export class ParentComponent {
constructor() { }
message:string;
receiveMessage($event) {
this.message = $event
}
}
child.component.ts
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'child-component',
template: `
<button (click)="sendMessage()">Send Message</button>
`,
styleUrls: ['./child.component.css']
})
export class ChildComponent {
message: string = "Hello!"
@Output() messageEvent = new EventEmitter<string>();
constructor() { }
sendMessage() {
this.messageEvent.emit(this.message)
}
}
3. Fratelli
Figlio> Genitore> Figlio
Cerco di spiegare altri modi di comunicare tra fratelli di seguito. Ma potresti già capire uno dei modi di comprendere i metodi sopra.
parent.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'parent-component',
template: `
Message: {{message}}
<child-one-component (messageEvent)="receiveMessage($event)"></child1-component>
<child-two-component [childMessage]="message"></child2-component>
`,
styleUrls: ['./parent.component.css']
})
export class ParentComponent {
constructor() { }
message: string;
receiveMessage($event) {
this.message = $event
}
}
bambini-one.component.ts
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'child-one-component',
template: `
<button (click)="sendMessage()">Send Message</button>
`,
styleUrls: ['./child-one.component.css']
})
export class ChildOneComponent {
message: string = "Hello!"
@Output() messageEvent = new EventEmitter<string>();
constructor() { }
sendMessage() {
this.messageEvent.emit(this.message)
}
}
bambini-two.component.ts
import { Component, Input } from '@angular/core';
@Component({
selector: 'child-two-component',
template: `
{{ message }}
`,
styleUrls: ['./child-two.component.css']
})
export class ChildTwoComponent {
@Input() childMessage: string;
constructor() { }
}
4. Componenti non correlati
Tutti i metodi che ho descritto di seguito possono essere utilizzati per tutte le opzioni di cui sopra per la relazione tra i componenti. Ognuno ha i suoi vantaggi e svantaggi.
Condivisione dei dati con un servizio
Quando si trasmettono dati tra componenti privi di una connessione diretta, come fratelli, nipoti, ecc., È necessario utilizzare un servizio condiviso. Quando disponi di dati che dovrebbero essere sempre sincronizzati, trovo l'RxJS BehaviorSubject molto utile in questa situazione.
data.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable()
export class DataService {
private messageSource = new BehaviorSubject('default message');
currentMessage = this.messageSource.asObservable();
constructor() { }
changeMessage(message: string) {
this.messageSource.next(message)
}
}
first.component.ts
import { Component, OnInit } from '@angular/core';
import { DataService } from "../data.service";
@Component({
selector: 'first-componennt',
template: `
{{message}}
`,
styleUrls: ['./first.component.css']
})
export class FirstComponent implements OnInit {
message:string;
constructor(private data: DataService) {
// The approach in Angular 6 is to declare in constructor
this.data.currentMessage.subscribe(message => this.message = message);
}
ngOnInit() {
this.data.currentMessage.subscribe(message => this.message = message)
}
}
second.component.ts
import { Component, OnInit } from '@angular/core';
import { DataService } from "../data.service";
@Component({
selector: 'second-component',
template: `
{{message}}
<button (click)="newMessage()">New Message</button>
`,
styleUrls: ['./second.component.css']
})
export class SecondComponent implements OnInit {
message:string;
constructor(private data: DataService) { }
ngOnInit() {
this.data.currentMessage.subscribe(message => this.message = message)
}
newMessage() {
this.data.changeMessage("Hello from Second Component")
}
}
Condivisione dei dati con un percorso
A volte è necessario non solo passare dati semplici tra i componenti, ma salvare un po 'di stato della pagina. Ad esempio, vogliamo salvare alcuni filtri nel mercato online, quindi copiare questo link e inviarlo a un amico. E ci aspettiamo che apra la pagina nello stesso stato di noi. Il primo, e probabilmente il più veloce, modo per farlo sarebbe usare i parametri della query .
I parametri della query sono più simili a quelli di /people?id=
doveid
può eguagliare qualsiasi cosa e puoi avere tutti i parametri che desideri. I parametri della query sarebbero separati dal carattere e commerciale.
Quando si lavora con i parametri della query, non è necessario definirli nel file delle rotte e possono essere denominati parametri. Ad esempio, prendi il seguente codice:
page1.component.ts
import {Component} from "@angular/core";
import {Router, NavigationExtras} from "@angular/router";
@Component({
selector: "page1",
template: `
<button (click)="onTap()">Navigate to page2</button>
`,
})
export class Page1Component {
public constructor(private router: Router) { }
public onTap() {
let navigationExtras: NavigationExtras = {
queryParams: {
"firstname": "Nic",
"lastname": "Raboy"
}
};
this.router.navigate(["page2"], navigationExtras);
}
}
Nella pagina di ricezione, riceveresti questi parametri di query come il seguente:
page2.component.ts
import {Component} from "@angular/core";
import {ActivatedRoute} from "@angular/router";
@Component({
selector: "page2",
template: `
<span>{{firstname}}</span>
<span>{{lastname}}</span>
`,
})
export class Page2Component {
firstname: string;
lastname: string;
public constructor(private route: ActivatedRoute) {
this.route.queryParams.subscribe(params => {
this.firstname = params["firstname"];
this.lastname = params["lastname"];
});
}
}
NGRX
L'ultimo modo, che è più complicato ma più potente, è usare NgRx . Questa libreria non è per la condivisione dei dati; è una potente libreria di gestione dello stato. Non posso in un breve esempio spiegare come usarlo, ma puoi andare sul sito ufficiale e leggere la documentazione a riguardo.
Per me, NgRx Store risolve diversi problemi. Ad esempio, quando si ha a che fare con osservabili e quando la responsabilità di alcuni dati osservabili è condivisa tra diversi componenti, le azioni del negozio e il riduttore assicurano che le modifiche ai dati vengano sempre eseguite "nel modo giusto".
Fornisce inoltre una soluzione affidabile per la memorizzazione nella cache delle richieste HTTP. Sarai in grado di memorizzare le richieste e le loro risposte in modo da poter verificare che la richiesta che stai facendo non abbia ancora una risposta memorizzata.
Puoi leggere su NgRx e capire se ne hai bisogno nella tua app o meno:
Infine, voglio dire che prima di scegliere alcuni dei metodi per la condivisione dei dati è necessario capire come questi dati verranno utilizzati in futuro. Voglio dire, forse proprio ora puoi usare solo un @Input
decoratore per condividere un nome utente e un cognome. Quindi aggiungerai un nuovo componente o un nuovo modulo (ad esempio un pannello di amministrazione) che richiede ulteriori informazioni sull'utente. Ciò significa che potrebbe essere un modo migliore per utilizzare un servizio per i dati dell'utente o un altro modo per condividere i dati. Devi pensarci di più prima di iniziare a implementare la condivisione dei dati.