javascript - Anropa Angular2-funktioner i serie, en efter en
Jag har en tjänst i ett Angular2-projekt som tar några parametrar och returnerar en värdelista för att fylla drop-down-menyer i ett formulär. När formulärkomponenten initieras, behöver jag anropa samma tjänst flera gånger med olika parametrar för att definiera ett antal olika drop-down-menyer, men om jag anropar dem alla så skriver det sista anropet över de tidigare, antagligen eftersom de efterföljande anropen överskriver eller avbryter de tidigare hämtningarna.
Jag har delat upp varje anrop i sin egen funktion, men jag behöver ett sätt att anropa varje funktion i serie så att den andra inte anropas förrän den första är klar. Varje funktion fungerar på egen hand, men om jag anropar mer än en, lyckas bara den sista, och den första misslyckas med fel (eftersom tjänsten själv avslutar den pågående hämtningen när den anropas med nya parametrar innan den är klar).
this.fetchValueListOne();
this.fetchValueListTwo();
this.fetchValueListThree();
Jag försökte få detta att fungera med promises, men hamnade ganska snabbt i ett scope-helvete eftersom jag var tvungen att skicka de tjänster jag ville komma åt in i funktionerna och sedan inte kunde få ut resultatdata igen - varje tjänsteförfrågan tar tre parametrar och sätter sedan en specifik this.valueList[]-variabel definierad i komponenten och använd på formuläret.
Jag försökte också skapa en lista över funktionerna som variabler och sedan iterera över dem, men jag stötte på samma scope-problem som med promises.
Tjänsten returnerar ett Observable, funktionerna prenumererar på det Observable, hämtar datan och tilldelar den till en array-variabel i komponenten som en dropdown-värdelista är bunden till.
Funktionerna ser ut så här:
fetchValueListOne() {
this.dataSvc.getValueList('Val-List-One', this.stateSvc.currentContext, this.stateSvc.currentLanguageCode)
.map(response => response.json())
.subscribe(
data => {
this.valListOne = data;
},
err => console.log('Error', err),
() => {
console.log('this.valListOne', this.valListOne);
}
);
}
Svar #1
SrAxi pekade mig i rätt riktning, och slutligen löste jag problemet på följande sätt där Promises visade sig vara den bästa lösningen, specifikt löste Promise/.then-mekanismen problemet på ett bra sätt.
fetchValueList(listCode): Promise<any> {
return this.dataSvc.getValueList(listCode, this.stateSvc.currentContext, this.stateSvc.currentLanguageCode)
.map(response => response.json())
.toPromise();
}
initializeDropDowns() {
this.fetchValueList('First-Val-List')
.then(data => {
this.firstValList = data;
return this.fetchValueList('Second-Val-List')
}).then(data => {
this.secondValList = data;
return this.fetchValueList('Third-Val-List')
}).then(data => {
this.thirdValList = data;
}) }
Jag definierade funktionerna i komponenten och kallade sedan initializeDropDowns() i ngOnInit.
Funktionen fetchValueList returnerar ett Promise, så det första anropet skickar det första listCode och när Promiset löses, är returvärdet i data-variabeln i .then-blocket där vi kan tilldela det till variabeln this.firstValList. Eftersom funktionen har returnerat data, vet vi att tjänsten har avslutats och det är säkert att anropa igen med det andra listCode, returvärdet är i data-variabeln i nästa .then-block och vi tilldelar det till variabeln this.secondValList.
Vi kan kedja detta så många gånger som behövs för att fylla alla variabler, och i den sista kodblocket utelämnar vi helt enkelt returuttalandet och blocket avslutas.
Detta är ett mycket specifikt användningsfall där vi har en enda tjänst som behöver anropas flera gånger när komponenten initieras, och där tjänsten måste slutföra sin hämtning och returnera ett värde innan den kan anropas igen, men i detta fall var Promise/.then-metoden idealisk.
Svar #2
Anropa funktionerna när du har mottagit data. Till exempel:
this.fetchValueListOne().subscribe((firstData) => {
this.fetchValueListTwo(firstData);
// Do something with firstData
}
);
this.fetchValueListTwo().subscribe((secondData) => {
this.fetchValueListThree(secondData);
// Do something with secondData
}
);
this.fetchValueListThree().subscribe((thirdData) => {
// Do something with thirdData
}
);
Och deklarera dessa funktioner som Observable, såsom:
public fetchValueListOne(): Observable<any> { // Get firstData }
public fetchValueListTwo(): Observable<any> { // Get secondData}
public fetchValueListThree(): Observable<any> { // Get thirdData}
På detta sätt kommer du vara säker på att när du anropar en funktion har du datan från den föregående.
