Reputation: 11
I am using ng2-google-charts to display some data in a donut chart in my Angular app. In the app, I pull a user from a JSON server, do some relatively simple calculations, and output the results of those calculations in the donut chart. When data is passed straight into the graph it works fine, but when I pass user information that is calculated into the graph is displays nothing. I suspect this is because it is loading data before the calculations are complete.
I have tried using an *ngIf on the surrounding div to wait for the user to complete loading and calculations to complete, but that seems to do nothing. I know I can probably use the resolved promise to my advantage (I'm using that to make sure the page doesn't load before the data does), but I'm still not really sure how to tie that in with ng2-google-charts. The ng2-google-charts documentation doesn't seem to have any information regarding the matter. I'm still trying to wrap my head around asynchronous functions, so any help would be greatly appreciated.
home.component.ts
userLoaded: Promise<boolean>;
creditsCompleted = 0;
creditsInProgress = 0;
creditsLeft = 0;
getUser() {
this.eventsService.user$.subscribe((user) => {
this.user = user;
if (user) {
this.calculateUserCredits(); // the function that does our calculations
this.userLoaded = Promise.resolve(true);
}
})
}
calculateUserCredits() {
// we calculate stuff and assign to the credits variables
}
public pieChart: GoogleChartInterface = {
chartType: 'PieChart',
dataTable: [
['Task', 'Total Credits'],
['Completed', this.creditsCompleted],
['In Progress', this.creditsInProgress],
['Remaining', this.creditsLeft]
],
options: {'title': 'Credit Breakdown',
'pieHole':0.4,
'pieSliceTextStyle': {
'color':'black'
},
'fontName':'Roboto',
'backgroundColor' : {
'fill' : 'transparent'
}
},
};
home.component.html
<div class="col-lg-8 bodyFont" style="width: 100%; height: 100%">
<google-chart class="p-0 m-0" [data]="pieChart"></google-chart>
</div>
Upvotes: 1
Views: 1139
Reputation: 11
I'm not sure if this is the most elegant solution, but it turns out that my errors went a bit deeper than expected. Converting calculateUserCredits() to an observable allowed my program to wait for my calculations to finish, but I overlooked one crucial detail -- I wasn't waiting on the chart component to finish loading before calculating user credits, meaning that I couldn't set the data table again or redraw the chart. Using the built-in chartReady event and a behavior subject, I was able wait until the chart was finished loading to reassign my data to the dataTable after calculation and force a redraw. This could probably be refactored or simplified in some way, but this worked for me.
home.component.ts
userLoaded: Promise<boolean>;
_chartReady: BehaviorSubject<Boolean> = new BehaviorSubject<Boolean>(false);
chartReady$ = this._chartReady.asObservable();
creditsCompleted = 0;
creditsInProgress = 0;
creditsLeft = 0;
ngOnInit() {
this.getUser();
}
getUser() {
this.eventsService.user$.subscribe((user) => {
this.user = user;
if (user) {
this.calculateUserCredits();
this.userLoaded = Promise.resolve(true);
}
});
}
calculateUserCredits() {
// calculate stuff here...
this.chartReady$.subscribe(value => {
console.log(value);
if (value === true) {
this.pieChart.component.data.dataTable = [
['Task', 'Total Credits'],
['Completed', this.creditsCompleted],
['In Progress', this.creditsInProgress],
['Remaining', this.creditsLeft]
];
this.pieChart.component.draw();
}
});
}
public pieChart: GoogleChartInterface = {
chartType: 'PieChart',
dataTable: [
['Task', 'Total Credits'],
['Completed', this.creditsCompleted],
['In Progress', this.creditsInProgress],
['Remaining', this.creditsLeft]
],
options: {'title': 'Credit Breakdown',
'pieHole':0.4,
'pieSliceTextStyle': {
'color':'black'
},
'fontName':'Roboto',
'backgroundColor' : {
'fill' : 'transparent'
}
},
};
public ready(event: ChartReadyEvent) {
this._chartReady.next(true);
}
home.component.html
<div class="col-lg-8 bodyFont" style="width: 100%; height: 100%">
<google-chart class="p-0 m-0" [data]="pieChart" (chartReadyOneTime)="this.ready($event)"></google-chart>
</div>
Upvotes: 0
Reputation: 18805
You can return an Observable from your calculatUserCredits
method like so and subscribe to it:
ngOnInit()
{
this.calculatUserCredits().subscribe(value => {
// do something to trigger your *ngIf here.
});
}
public calculatUserCredits(): Observable<any>{
// return a bool, or even the calculated data.
return of("some value");
}
Here is a working example: https://stackblitz.com/edit/angular-e5ggc2
Upvotes: 0