Reputation: 93
I am trying to use data returned from an Angular Observable Service in a function outside the subscription. I can successfully access the data in the View Component (.html), however when I am unable to access the data from another function in the component.ts file. The value is returned as 'undefined' when trying to access from the 'drawChart' function below.
How do I access the specialistCount data from the drawChart function?
My component code is as follows: dashboard.component.ts
ngOnInit() {
this.getUserCounts();
this.drawCharts();
}
getUserCounts() {
this.userService.getUserCount('all').subscribe(totalUserCount => { this.totalUserCount = totalUserCount; });
this.userService.getUserCount('specialist').subscribe(specialistCount => { this.specialistCount = specialistCount; });
this.userService.getUserCount('delegate').subscribe(delegateCount => { this.delegateCount = delegateCount; });
this.userService.getUserCount('practioner').subscribe(practionerCount => { this.practionerCount = practionerCount; });
this.userService.getUserCount('admin').subscribe(adminCount => { this.adminCount = adminCount; });
}
drawCharts() {
console.log('The valiue:' + this.specialistCount);
this.pieChartData = {
chartType: 'PieChart',
dataTable: [
['Users', 'Hours per Day'],
['Specialists', this.specialistCount],
['Delegates', this.delegateCount],
['practioners', 15],
['QMS Staff', 0]
],
options: {'title': 'Users'},
};
}
My Service code is: user.service.ts
getUserCount(role) {
const headers = new Headers();
this.loadToken();
headers.append('Authorization', this.authToken);
headers.append('Content-Type', 'application/json');
return this.http.get(this.apiUrl + '/users/count/' + role, { headers: headers }).map(res => res.json());
}
Upvotes: 0
Views: 240
Reputation: 93
As per Lazar's answer I have modified my code to use a forkJoin and call the populateGrid function inside the Observable.
New code as follows:
ngOnInit() {
this.getUserCounts();
}
getUserCounts() {
forkJoin(this.userService.getUserCount('all'),
this.userService.getUserCount('specialist'),
this.userService.getUserCount('delegate'),
this.userService.getUserCount('practioner'),
this.userService.getUserCount('admin')
).subscribe(
returnedValues => {
this.totalUserCount = returnedValues[0];
this.specialistCount = returnedValues[1];
this.delegateCount = returnedValues[2];
this.practionerCount = returnedValues[3];
this.adminCount = returnedValues[4];
this.drawCharts();
}
);
}
drawCharts() {
this.pieChartData = {
chartType: 'PieChart',
dataTable: [
['Users', 'Hours per Day'],
['Specialists', this.specialistCount],
['Delegates', this.delegateCount],
['Practioners', this.practionerCount],
['QMS Staff', this.adminCount]
],
options: {'title': 'Users'},
};
}
Upvotes: 0
Reputation: 19764
I am trying to use data returned from an Angular Observable Service in a function outside the subscription.
You cannot do this. This is because the HTTP observables are asynchronous.
let foo
console.log('before', foo)
this.https.get('something').subscribe(result => {
foo = result
console.log('inside', foo)
})
console.log('after', foo)
Assuming that the observable returns a number 42 (result
is 42), this will print the following:
before undefined
after undefined
inside 42
The first two lines would be printed immediately. The last line would be printed only after the browser sends the request to the server, the request travels to it through cables across the Earth, the response arrives and is parsed as JSON.
You need to call your getUserCount
method inside the subscribe method. Seems like you need to make all five requests before you have enough information to run the getUserCount
function, so you'll need to wait for all five requests to complete to run it.
You can see here how to do parallel requests.
To do the requests in parallel (for requests which are not dependant of one another), use the
forkJoin
static operator.return Observable.forkJoin( this.http.get('url/1'), this.http.get('url/2'), ) .subscribe(([res1, res2]) => { // res1 and res2 available after both requests are completed })
Note that this has nothing to do with Angular -- it's only about RxJS and about the asynchronous nature of HTTP requests.
Upvotes: 2