J'ai une question à propos de la transmission de données dans Angular.
Tout d'abord, je n'ai pas de structure en tant que <parent><child [data]=parent.data></child></parent>
Ma structure est
<container>
<navbar>
<summary></summary>
<child-summary><child-summary>
</navbar>
<content></content>
</container>
Donc, dans <summary />
j'ai une sélection qui envoie une valeur à <child-summary />
et <content />
.
La méthode OnSelect est bien utilisée avec (changement) dans le composant <summary />
.
J'ai donc essayé avec les directives @Input
, @Output
et @EventEmitter
, mais je ne vois pas comment récupérer l'événement en tant que @Input du composant, à moins de passer au modèle parent/enfant. Tous les exemples que j'ai fondés ont une relation entre composants.
EDIT: Exemple avec BehaviorSubject ne fonctionne pas (tous les services connectés à l'API fonctionnent bien, seule l'observable est déclenchée au démarrage, mais pas lorsque la valeur de sélection a été modifiée)
shared service = company.service.ts (utilisé pour récupérer les données de l'entreprise)
import { Injectable } from '@angular/core';
import { Headers, Http, Response } from '@angular/http';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/toPromise';
@Injectable()
export class SrvCompany {
private accountsNumber = new BehaviorSubject<string[]>([]);
currentAccountsNumber = this.accountsNumber.asObservable();
changeMessage(accountsNumber: string[]) {
this.accountsNumber.next(accountsNumber);
}
private _companyUrl = 'api/tiers/';
constructor(private http: Http) { }
getSociete(): Promise<Response> {
let url = this._companyUrl;
return this.http.get(url).toPromise();
}
}
invoice.component.ts ("l'enfant")
import { Component, OnInit, Input } from '@angular/core';
import { Headers, Http, Response } from '@angular/http';
import { SrvInvoice } from './invoice.service';
import { SrvCompany } from '../company/company.service';
@Component({
selector: 'invoice',
templateUrl: 'tsScripts/invoice/invoice.html',
providers: [SrvInvoice, SrvCompany]
})
export class InvoiceComponent implements OnInit {
invoice: any;
constructor(private srvInvoice: SrvInvoice, private srvCompany: SrvCompany)
{
}
ngOnInit(): void {
//this.getInvoice("F001");
// Invoice data is linked to accounts number from company.
this.srvCompany.currentAccountsNumber.subscribe(accountsNumber => {
console.log(accountsNumber);
if (accountsNumber.length > 0) {
this.srvInvoice.getInvoice(accountsNumber).then(data => this.invoice = data.json());
}
});
}
//getInvoice(id: any) {
// this.srvInvoice.getInvoice(id).then(data => this.invoice = data.json());
//}
}
company.component.ts (le "parent" déclencheur)
import { Component, Inject, OnInit, Input } from '@angular/core';
import { Headers, Http, Response } from '@angular/http';
import { SrvCompany } from './company.service';
@Component({
selector: 'company',
templateUrl: 'tsScripts/company/company.html',
providers: [SrvCompany]
})
export class CompanyComponent implements OnInit {
societes: any[];
soc: Response[]; // debug purpose
selectedSociete: any;
ville: any;
ref: any;
cp: any;
accountNumber: any[];
constructor(private srvSociete: SrvCompany)
{
}
ngOnInit(): void {
this.getSocietes();
}
getSocietes(): void {
this.srvSociete.getSociete()
.then(data => this.societes = data.json())
.then(data => this.selectItem(this.societes[0].Id));
}
selectItem(value: any) {
this.selectedSociete = this.societes.filter((item: any) => item.Id === value)[0];
this.cp = this.selectedSociete.CodePostal;
this.ville = this.selectedSociete.Ville;
this.ref = this.selectedSociete.Id;
this.accountNumber = this.selectedSociete.Accounts;
console.log(this.accountNumber);
this.srvSociete.changeMessage(this.accountNumber);
}
}
Dans ce cas, vous souhaitez utiliser un service partagé, car vos composants sont structurés comme des frères et soeurs et des petits-enfants. Voici un exemple tiré d'une vidéo pour laquelle j'ai créé une vidéo sur le partage de données entre composants qui résout ce problème.
Commencez par créer un BehaviorSubject dans le service
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@Injectable()
export class DataService {
private messageSource = new BehaviorSubject("default message");
currentMessage = this.messageSource.asObservable();
constructor() { }
changeMessage(message: string) {
this.messageSource.next(message)
}
}
Puis injectez ce service dans chaque composant et abonnez-vous à l'observable.
import { Component, OnInit } from '@angular/core';
import { DataService } from "../data.service";
@Component({
selector: 'app-parent',
template: `
{{message}}
`,
styleUrls: ['./sibling.component.css']
})
export class ParentComponent implements OnInit {
message:string;
constructor(private data: DataService) { }
ngOnInit() {
this.data.currentMessage.subscribe(message => this.message = message)
}
}
Vous pouvez modifier la valeur de l'un des composants et la valeur sera mise à jour, même si vous n'avez pas la relation parent/enfant.
import { Component, OnInit } from '@angular/core';
import { DataService } from "../data.service";
@Component({
selector: 'app-sibling',
template: `
{{message}}
<button (click)="newMessage()">New Message</button>
`,
styleUrls: ['./sibling.component.css']
})
export class SiblingComponent implements OnInit {
message:string;
constructor(private data: DataService) { }
ngOnInit() {
this.data.currentMessage.subscribe(message => this.message = message)
}
newMessage() {
this.data.changeMessage("Hello from Sibling")
}
}
si les composants ne sont pas liés, vous devez utiliser le service
https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service
Il y a deux solutions pour cela.
Cela peut être fait par un service partagé en utilisant des observables.
Vous pouvez utiliser ngrx/store pour cela. Ceci est similaire à Redux Arch. Vous obtiendrez des données de l'état.