I am retrieving database data using a service in TypeScript
and assigning data in a global variable as follows:
parentMenu: any[] = []; //Global var
LoadParentMenu() {
this.menuService.getParentMenu().subscribe(result => this.parentMenu = result); //Assigning value here
}
LoadChildMenu() {
console.log(this.parentMenu); //Willing to use the global variable in the second function
}
I know, it can be done as follows calling the second function in the first one that worked perfectly but doesn't serve my purpose:
LoadParentMenu() {
this.LoadChildMenu(result); //Passing data in the second function
}
But my requirement is to get data from two services, bind them to a global array variable and finally use those in another method (Third method actually). I tried to do it as follows that returns undefined in the console:
parentMenu: any[] = []; //Global var 1
childMenu: any[] = []; //Global var 2
LoadParentMenu() {
this.menuService.getParentMenu().subscribe(result => this.parentMenu = result); //Assigning value here
}
LoadChildMenu() {
this.menuService.getParentMenu().subscribe(result => this.childMenu = result); //Assigning value here
}
LoadThirdFunc() {
console.log(this.parentMenu);
console.log(this.childMenu);
}
In the third function, I require to do changes passing the two global variables as follows:
const mergeById = (array1, array2) =>
array1.map(parent => ({
...parent,
childMenu: array2.filter((child) => child && (child.parentMenu === parent.menuNo))
.map(child => child && child.menuName)
}));
var result = mergeById(array1, array2)
.filter(x => x.childMenu && x.childMenu.length > 0);
Is there any appropriate or easy way that I can do the above?
CodePudding user response:
Sounds to me this would be a perfect use for observables, also if this is not changing data, shareReplay
could be good use to not trigger the http-requests again (assuming they are http-requests...)
Service:
menus$ = forkJoin([this.LoadParentMenu(), this.LoadChildMenu()]).pipe(shareReplay(1))
forkJoin runs these requests in parallel and returns an array with 2 items with your data, as so in pseudo:
[loadParentMenuResultHere, loadChildMenuResultHere]
Now you can subscribe to menus$
where ever you need it, I like async
pipe as it unsubscribes for you as well, so I recommend you that if possible.
If you even want to perform your third function by default, you can chain that there as well and you have an already structured array per your requirements, so something like this:
menus$ = forkJoin([this.LoadParentMenu(), this.LoadChildMenu()]).pipe(
map( /** do your magic here and return the data structure you want! **/ )
shareReplay(1)
);
CodePudding user response:
It returns undefined because typescript executes line by line, console.log is called before data is fetched from server. You can combine those two reqs into one and then it will only resolve when both reqs data is available
const promises = [];
promises.push(this.menuService.getParentMenu());
promises.push(this.menuService.getParentMenu());
Promise.all(promises).then(responselist=>{
//call any function of your choice, responselist will be an array of two results
// of your services
})
//if you are using angular then you can do something like this
import {Observable} from 'rxjs/Rx';
const reqs: Observable<any>[] = [];
reqs.push(this.menuService.getParentMenu());
reqs.push(this.menuService.getParentMenu());
Observable.forkJoin(reqs).subscribe(responseList => {
this.parentMenu = responseList[0];
this.childMenu = responseList[1];
//Or you loop through responselist
responseList.map((res,index)){}
});