Je développe une application en utilisant angular2. J'ai un scénario où je dois passer des données complexes (tableau d'objets) d'un composant à un autre composant (ils ne sont pas parent-enfant, ils sont deux composants séparés) lors du routage (à l'aide de router.navigate ()). Je l'ai googlé et la plupart des résultats décrivent le scénario de composants qui sont parent-enfant. J'ai parcouru les résultats et trouvé ces moyens de transmettre les données.
1) Créer un service partagé 2) Passer comme paramètres de route
La deuxième approche fonctionne pour moi (même si je n'aime pas cela lorsque j'ai des données complexes comme expliqué ci-dessus). Je ne suis pas en mesure de partager les données à l'aide d'un service partagé ..___ Ma question est donc la suivante: la transmission de données entre composants à l'aide de services ne fonctionne-t-elle que lorsque les composants sont en relation parent-enfant? Indiquez-moi également s’il existe d’autres moyens privilégiés de transmettre des données d’un composant à un autre.
Mise à jour: J'ajoute un peu de code de mon scénario. Faites-moi savoir mon erreur sur la raison pour laquelle la transmission de données via des services partagés ne fonctionne pas.
J'ai 2 composants: 1) SearchComponent 2) TransferComponent Je règle les données dans SearchComponent et je veux accéder aux données dans TransferComponent via utilityService.
Service public:
import {Injectable} from "@angular/core";
@Injectable()
export class UtilityService{
constructor(){
}
public bioReagentObject = [];
routeBioReagentObj(bioReagentObj){
console.log("From UtilityService...", bioReagentObj);
for (let each of bioReagentObj)
this.bioReagentObject.Push(each)
// console.log("From UtilityService",this.bioReagentObject);
}
returnObject(){
console.log("From UtilityService",this.bioReagentObject);
return this.bioReagentObject
}
}
searchcomponent.ts
import {UtilityService} from "../services/utilityservice.component";
import {Component, OnInit, OnDestroy, Input} from '@angular/core';
@Component({
selector: 'bioshoppe-search-details',
providers: [UtilityService],
templateUrl: 'app/search/searchdetails.component.html',
styleUrls: ['../../css/style.css']
})
export class SearchDetailsComponent implements OnInit, OnDestroy {
constructor(private route: ActivatedRoute,
private utilityService: UtilityService,
private router: Router) {
}
@Input() selected: Array<String> = [{barcode:123, description:"xyz"}];
//This method is called from .html and this.selected has the data to be shared.
toTransfer() {
this.utilityService.routeBioReagentObj(this.selected);
this.router.navigate(['/transfer']);
}
}
TransferService.ts
import {Component, Input, OnInit, OnDestroy} from '@angular/core';
import {TransferService} from "../services/transferservice.component";
import {UserService} from "../services/userservice.component";
import {SearchService} from "../services/searchservice.component";
import {ActivatedRoute} from '@angular/router';
import {UtilityService} from "../services/utilityservice.component";
@Component({
selector: 'bioshoppe-transfer',
providers: [TransferService, UserService, SearchService, UtilityService],
templateUrl: 'app/transfer/transfer.component.html',
styleUrls: ['../../css/style.css', '../../css/transfer.component.css']
})
export class TransferComponent implements OnInit, OnDestroy{
constructor(private transferService: TransferService,
private userService: UserService,
private searchService: SearchService,
private utilityService: UtilityService,
private route: ActivatedRoute
) {
}
ngOnInit() {
// I am trying to access the data here, but it print "undefind"
console.log("From Transferpage",this.utilityService.returnObject());
}
}
Je suis sûr que quelque chose ne va pas, mais c'est simplement que je ne suis pas capable de le comprendre. Toute aide est appréciée.
camaron a raison. Votre erreur est que vous déclarez UtilityService
deux fois :
SearchComponent
.TransferComponent
.Vous devez déclarer le service UNIQUEMENT UNE FOIS pour vous assurer que les deux composants obtiennent la même instance. Pour cela, vous pouvez choisir l’une de ces options:
@NgModule
qui a à la fois SearchComponent
et TransferComponent
dans ses déclarations . 9 fois sur 10 c'est la bonne solution!@Component
qui est un parent de SearchComponent
et de TransferComponent
. Cela pourrait ne pas être réalisable selon l'apparence de votre arborescence de composants.En suivant l’option n ° 1, vous vous retrouvez avec:
@NgModule({
imports: [CommonModule, ...],
// Look, the components injecting the service are here:
declarations: [SearchComponent, TransferComponent, ...],
// Look, the service is declared here ONLY ONCE:
providers: [UtilityService, ...]
})
export class SomeModule { }
Ensuite, injectez UtilityService
dans les constructeurs de vos composants SANS REDÉCLARER IT chez les fournisseurs des composants:
@Component({
selector: 'foo',
template: '...',
providers: [] // DO NOT REDECLARE the service here
})
export class SearchComponent {
constructor(private utilityService: UtilityService) { }
}
@Component({
selector: 'bar',
template: '...',
providers: [] // DO NOT REDECLARE the service here
})
export class TransferComponent {
constructor(private utilityService: UtilityService) { }
}
Vous devez distinguer lorsque le service provient de NgModule ou d’autres composants.
Basics
Dans Angular2, vous avez une arborescence hiérarchique de composants avec une relation parent-enfant (comme vous l'avez remarqué). En même temps, tous les services sont injectés à l'aide d'injecteurs, qui forment également un arbre hiérarchique (parallèlement à la hiérarchie des composants). L'arborescence des injecteurs ne coïncide pas nécessairement avec l'arborescence des composants, car il pourrait y avoir des injecteurs mandataires du parent aux fins d'efficacité.
Comment ça marche
Le rôle des injecteurs est de prendre le service que vous définissez dans le constructeur et de l’injecter dans votre composant, c’est-à-dire de le trouver, de l'initier s'il n'est pas trouvé et de vous le fournir. Lorsque vous indiquez dans le constructeur que vous souhaitez un service, il va rechercher dans l’arbre d’injection de votre composant jusqu’à la racine (qui est NgModule) l’existence du service. Si l'injecteur découvre qu'il existe un fournisseur défini pour ce service mais aucune instance de service, il créera le service. Si aucun fournisseur, il continue à monter.
Ce que vous avez vu jusqu'à présent
Ce que vous avez vu, c’est que le composant parent définit le service par le biais de "fournisseurs", et que les injecteurs à la recherche du service montent d’un cran dans l’arborescence, trouvent le fournisseur, lancent le service et fournissent votre composant enfant. Pour que tous les composants d'un sous-arbre aient le même service, vous devez définir le fournisseur uniquement dans la racine commune du sous-arbre. Si vous voulez avoir le même service pour tout le module, vous devez définir ce service chez les fournisseurs de module. C'est ce qu'on appelle le service Singleton.
Quelques extra
Normalement, si vous souhaitez injecter un service et que vous ne le trouvez pas jusqu'à la racine, vous obtiendrez une erreur lors de la compilation/exécution. Mais si vous définissez que vous souhaitez injecter le service Facultatif, l'injecteur n'échouera pas si le fournisseur de ce service n'est pas trouvé.
Plus ou moins...
Quelques liens utiles:
Vous pouvez atteindre cet objectif en partageant des données entre deux composants à l’aide d’observables.
Je n’ai pas écrit ce billet mais c’est très utile et facile à comprendre -
Un article rapide pour montrer un exemple de quelque chose qui m’a coincé pendant un moment - comment communiquer entre les composants dans Angular 2/4.
La solution consiste à utiliser un observable et un sujet (qui est un type d'observable)