0

My HTML markup look as follows where i am using piechart of NG2-Chart library which has dependency on chart.js:

<h2>Home</h2>
<div style="display: block">
    <canvas baseChart class="chart"
            [data]="pieChartData"
            [labels]="pieChartLabels"
            [chartType]="pie"
            (chartHover)="chartHovered($event)"
            (chartClick)="chartClicked($event)">
    </canvas>
</div>

I have written following code add it works perfectly fine. I can see the graph and get calls to eventhandlers too. My component code (working) looks as follows:

import {Component, OnInit, AfterViewInit, AfterContentInit} from '@angular/core';
import {NgClass} from '@angular/common';

import {PieChartData} from '../shared/pie-chart-data';
import {HotelsService} from '../components/hotel/hotels.service';
import {Hotel} from '../entities/hotel';


import * as _ from 'underscore/underscore';

@Component({
    selector:'home'
    , templateUrl:'app/home/home.component.html'
})
export class HomeComponent implements OnInit{
    hotels: Hotel[];
    hotelCountByCity; 
    data = new PieChartData();

    pieChartData = [];
    pieChartLabels=[];

    constructor(private _hotelsService: HotelsService){}

    ngOnInit(){
        this.getActiveHotelsByCity();        

        console.log("On Init");
    }

    // events
    public chartClicked(e:any):void {
        // TODO : should open another chart which is not decided.
    }

    public chartHovered(e:any):void {
        // TODO : do something
    }

    private getActiveHotelsByCity(){ 
        //this.data.pieChartType = "pie";
        this.pieChartLabels = ["One", "Two", "Three"]; 
        this.pieChartData = [100,200,300];
    }
}

But When i try to get the data from web service and assign it to piechart, I get weird errors. My component code (not working) :

import {Component, OnInit, AfterViewInit, AfterContentInit} from '@angular/core';
import {NgClass} from '@angular/common';

import {PieChartData} from '../shared/pie-chart-data';
import {HotelsService} from '../components/hotel/hotels.service';
import {Hotel} from '../entities/hotel';

import * as _ from 'underscore/underscore';

@Component({
    selector:'home'
    , templateUrl:'app/home/home.component.html'
})
export class HomeComponent implements OnInit{
    hotels: Hotel[];
    hotelCountByCity; 
    data = new PieChartData();

pieChartData = [];
pieChartLabels=[];

constructor(private _hotelsService: HotelsService){}

ngOnInit(){
    this.getActiveHotelsByCity();        

    console.log("On Init");
}

// events
public chartClicked(e:any):void {
    // TODO : should open another chart which is not decided.
}



   public chartHovered(e:any):void {
        // TODO : do something
    }

    private getActiveHotelsByCity(){  
        this._hotelsService.getAllActiveHotels()
                                .subscribe(
                                    res => this.hotelCountByCity =
                                                    _.countBy(
                                                        res.data.hotels
                                                        ,function(hotel: Hotel) {
                                                            return hotel.address.city;
                                                        })
                                    ,null
                                    , ()=> {
                                        this.pieChartLabels = _.keys(this.hotelCountByCity);
                                        this.pieChartData = _.values(this.hotelCountByCity);
                                        console.log("Reached success part of request");
                                    }
                                );
    }
}

The stack tress for error I get at first is as follows:

EXCEPTION: Uncaught (in promise): TypeError: Cannot set property stack of [object Object] which has only a getter TypeError: Cannot set property stack of [object Object] which has only a getter at assignAll (http://localhost:3000/node_modules/zone.js/dist/zone.js:704:29) at ViewWrappedError.ZoneAwareError (http://localhost:3000/node_modules/zone.js/dist/zone.js:775:16) at ViewWrappedError.BaseError [as constructor] (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:1104:38) at ViewWrappedError.WrappedError [as constructor] (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:1133:20) at new ViewWrappedError (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:5106:20) at _View_HomeComponent_Host0.DebugAppView._rethrowWithContext (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:9427:27) at _View_HomeComponent_Host0.DebugAppView.detectChanges (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:9413:22) at ViewRef_.detectChanges (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:7398:24) at RouterOutlet.activate (http://localhost:3000/node_modules/@angular/router/bundles/router.umd.js:3458:46) at ActivateRoutes.placeComponentIntoOutlet (http://localhost:3000/node_modules/@angular/router/bundles/router.umd.js:2955:20) at ActivateRoutes.activateRoutes (http://localhost:3000/node_modules/@angular/router/bundles/router.umd.js:2933:26) at eval (http://localhost:3000/node_modules/@angular/router/bundles/router.umd.js:2902:23) at Array.forEach (native) at ActivateRoutes.activateChildRoutes (http://localhost:3000/node_modules/@angular/router/bundles/router.umd.js:2901:33) at ActivateRoutes.activate (http://localhost:3000/node_modules/@angular/router/bundles/router.umd.js:2896:18)

I realise this is not real error after digging around on internet. I found some advise on internet to locate the real error and the real error i found was:

"TypeError: Chart.controllers[meta.type] is not a constructor at Chart.Controller. (http://localhost:3000/node_modules/chart.js/dist/Chart.bundle.js:8508:24) at Object.helpers.each (http://localhost:3000/node_modules/chart.js/dist/Chart.bundle.js:9345:15) at Chart.Controller.buildOrUpdateControllers (http://localhost:3000/node_modules/chart.js/dist/Chart.bundle.js:8497:12) at Chart.Controller.initialize (http://localhost:3000/node_modules/chart.js/dist/Chart.bundle.js:8356:7) at new Chart.Controller (http://localhost:3000/node_modules/chart.js/dist/Chart.bundle.js:8339:6) at new Chart (http://localhost:3000/node_modules/chart.js/dist/Chart.bundle.js:10684:21) at BaseChartDirective.getChartBuilder (http://localhost:3000/node_modules/ng2-charts/components/charts/charts.js:73:16) at BaseChartDirective.refresh (http://localhost:3000/node_modules/ng2-charts/components/charts/charts.js:114:27) at BaseChartDirective.ngOnInit (http://localhost:3000/node_modules/ng2-charts/components/charts/charts.js:18:18) at Wrapper_BaseChartDirective.detectChangesInInputProps (/ChartsModule/BaseChartDirective/wrapper.ngfactory.js:89:53) at _View_HomeComponent0.detectChangesInternal (/AppModule/HomeComponent/component.ngfactory.js:74:32) at _View_HomeComponent0.AppView.detectChanges (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:9305:18) at _View_HomeComponent0.DebugAppView.detectChanges (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:9410:48) at _View_HomeComponent_Host0.AppView.detectViewChildrenChanges (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:9331:23) at _View_HomeComponent_Host0.detectChangesInternal (/AppModule/HomeComponent/host.ngfactory.js:33:8)"

I am not sure where to go from here. I have posted issue on ng2-charts gihub repo. I am stuck and i will really appreciate your help.

Darshan Puranik
  • 1,055
  • 3
  • 14
  • 36
  • hello can you show me console output of this.pieChartLabels = _.keys(this.hotelCountByCity); this.pieChartData = _.values(this.hotelCountByCity); you are doing mistake here. its not in format which is required by ng2chart. if possible add plnkr also – Amit kumar Jan 16 '17 at 07:34
  • ng2-chart lables is of type string[] and data of number []. I have used this same code before upgrading ng2-chart library and angular 2 final version. This problem occured when I updated the app. – Darshan Puranik Jan 16 '17 at 07:48
  • well i am using ng2-chart with angular 2.4.1 and ng2-charts:1.4.4. your pie label and data should be in this form pieChartLabels:string[] = ['string1', 'string2', 'string3']; but i if you use _.key it will product something like 0:'string1' but we want only string1 its index is not required. can you use foreach and push all these string data values using array push in a variable and then assign to pieChartLabels. – Amit kumar Jan 16 '17 at 08:00
  • and at the keep default values pieChartLabels:string[] = ['loading']; public pieChartData:number[] = [100]; can you try it once. – Amit kumar Jan 16 '17 at 08:02

1 Answers1

0

I did some research on internet and read the documentation. I couldn't find the definite answer for my problem. Following process worked for me:

  1. I downgraded chart.js from 2.4.0 to 2.3.0
  2. I added the boolean to my component to indicate data was received from RESTApi or not. I used that flag to display canvas using *ngIf.

HTML markup looks as follows:

<canvas 
            baseChart 
            class="chart"
            [data]="data.pieChartData"
            [labels]="data.pieChartLabels"
            [chartType]="data.pieChartType"
            (chartHover)="chartHovered($event)"
            (chartClick)="chartClicked($event)"
            *ngIf="isDataAvailable"
            >
    </canvas>
Darshan Puranik
  • 1,055
  • 3
  • 14
  • 36
  • so the problem is at the component initialization time there were no data in you chart ?? thats why you are using boolean. ? – Amit kumar Jan 18 '17 at 05:50
  • Strangely yes. But this problem wasnt there. – Darshan Puranik Jan 18 '17 at 06:53
  • thats why sir i asked you to keep default values pieChartLabels:string[] = ['loading']; public pieChartData:number[] = [100]; at the start of component so you don't face this error. can you try the same with 2.4.0 with setting initial value. – Amit kumar Jan 18 '17 at 06:59
  • static array of values will work anytime. Its the async HTTP call that i needed to handle. – Darshan Puranik Jan 18 '17 at 07:08
  • sir this static array is to create just chart. when it get async http response it will replace static array with new dynamic data then we will not get this error. so now we have how solution for this. either use *ngIf & wait for data or use some loading data default values & show message waiting for data. :) – Amit kumar Jan 18 '17 at 07:20
  • I like the *ngIf solution than loading some random values. Its not a good idea to feed random vals in prod environment anyways. Its a codesmell. If you like the ngIf solution then pls give upvote for my answer. – Darshan Puranik Jan 18 '17 at 09:09