Update data from Google Charts


#1

Hi all,
I’m working with the google charts on ionic 2 and by now I’m loving it.

But I have a problem … When I try to update the data in the graph it gives me an error about the container.

When the application starts I create 3 graphs dynamically, and what I want to do is that when the user refreshes the page, the data of these graphs are updated, without creating new graphs.

Error:

ERROR Error: The container #3 is not defined.
at g (polyfills.js:3)
at gvjs_Z.gvjs_.getContainer (jsapi_compiled_default_module.js:240)
at gvjs_Z.gvjs_.draw (jsapi_compiled_default_module.js:236)
at google-chart-component.ts:63
at t.invokeTask (polyfills.js:3)
at Object.onInvokeTask (core.es5.js:4136)
at t.invokeTask (polyfills.js:3)
at n.runTask (polyfills.js:3)
at invoke (polyfills.js:3)
at e (polyfills.js:2)

Anyone have any idea what it might be?

Thanks!


#2

Well, you obviously have to change line 27 of your code as the library you are using, as I read on the documentation you linked, requires you to add an additional variable there.

(Yep, sarcasm. Please provide us with the library you are using and the code you wrote to create these 3 graphs and containers. Otherwise it is impossible to help you.)


#3

Hi, thanks for replying.

Html:

  <ion-list>
    <ion-item no-lines *ngFor="let t of charts" [hidden]="!t.options.outros.visible">
      <ion-card *ngIf="t">
        <ion-card-header>
          <div class="row space-between-center">
            <span>{{t.options.outros.title}}</span>
            <ion-icon class="iconInfo" (click)='moreInfoTag(t);' name="information-circle"></ion-icon>
          </div>
        </ion-card-header>
        <div style=" height: 200px; margin-left: 3.5%" class="row center-center chart">
          <ion-spinner style="margin-top: 74px" [hidden]="loaded" name="crescent"></ion-spinner>
          <google-chart *ngIf="t" class="chart" id="{{t.id}}" [chartData]="t.data" [chartOptions]="t.options" chartType="{{t.options.chartType}}"></google-chart>
        </div>
      </ion-card>
    </ion-item>
  </ion-list>

Ts:

import { Component } from '@angular/core';
import { NavController, NavParams, ToastController, Events, MenuController } from 'ionic-angular';
import { Storage } from '@ionic/storage';

//import service
import { UserTagsService } from '../../providers/user-tags-service';

//import pages
import { MoreInfoTagPage } from '../more-info-tag-page/more-info-tag-page';

//impor translate
import { TranslateService } from 'ng2-translate';

//
import { GoogleChartComponent } from '../../components/google-charts/google-chart-component';
@Component({
  selector: 'page-menu-page',
  templateUrl: 'menu-page.html',
  providers: [UserTagsService, GoogleChartComponent]
})


export class MenuPage {

  tagsUserData: any;
  tagsUserInfo: any;

  tagsId: any;

  cache: boolean = false;
  charts: any = [];
  loaded: Boolean = false;


  selectedChart: any;
  userGroups = [];
  chartsData = [];
  tagsName = [];
  selectedGroup: any;


  constructor(public navCtrl: NavController,
    public navParams: NavParams,
    public tagService: UserTagsService,
    public storage: Storage,
    public toastCrtl: ToastController,
    public event: Events,
    public menu: MenuController,
    public translateService: TranslateService,
    public googleCharts: GoogleChartComponent) {

    //Set group selected by default
    this.selectedGroup = "all";
    this.getLogUser();
  }


  getLogUser() {
    this.storage.get('userId').then((userId) => {
      console.log('User id', userId);
    })
    //get the email of user loged in
    this.storage.get('userEmail').then((userEmail) => {
      console.log('User Email', userEmail);
    })

    //get the password of user loged in
    this.storage.get('userPassword').then((userPassword) => {
      console.log('User Password', userPassword);
    })
  }


  ionViewDidLoad() {

    this.storage.get('userId').then((userId) => {

      this.tagService.getTagsId(userId).subscribe(tagsId => {
        this.tagService.getInfoTags(userId).subscribe(infoTags => {
          this.tagsUserInfo = infoTags["body"].tagsInfo

          this.tagsId = [];
          this.tagsId = tagsId["body"]

          this.chartsData = []

          for (let i = 0; i < this.tagsId.length; i++) {
            this.tagService.getTagById(this.tagsId[i].tagId).subscribe(tag => {
              this.chartsData.push(tag["tagData"]["tagData"])
            })
          }

          for (let i = 0; i < this.chartsData.length; i++) {
            for (let data of this.chartsData[i]) {
              data[0] = new Date(data[0])
            }
          }

          for (let i = 0; i < this.chartsData.length; i++) {
            this.chartsData[i].unshift(['Dias', 'Indice', { type: 'number', role: 'annotation' }])
          }

          for (let i = 0; i < this.tagsUserInfo.length; i++) {
            this.userGroups.push(this.tagsUserInfo[i].group.group)
          }

          this.drawChart();
      
        })
      }, error => {
      });
    })
    this.event.subscribe('Loaded', (chartLoaded) => {
      this.loaded = chartLoaded;

    })
  }

  drawChart(){
        for (var i = 0; i < this.chartsData.length; i++) {
            this.charts.push({
              id: this.tagsId[i].tagId,
              data: this.chartsData[i],
              options: {
                tooltipWidth: 400,
                tooltipHeight: 200,
                pointSize: 5,
                chartArea: { width: '87%', top: '2%' },
                curveType: 'function',
                legend: { position: 'bottom' },
                series: {
                  0: { color: '#3cb371' },
                  viewWindowMode: 'explicit',
                  isStacked: 'false',
                  viewWindow: {
                    max: 10,
                    min: 0
                  },
                },
                hAxis: {
                  format: 'd/M',
                  gridlines: {
                    color: 'none'
                  }
                },
                vAxis: {
                  textColor: '#ffffff',
                },
                outros: {
                  title: this.tagsUserInfo[i].nameTag,
                  group: this.tagsUserInfo[i].group.group,
                  local: this.tagsUserInfo[i].local.local,
                  meaning: this.tagsUserInfo[i].meaning.meaning,
                  visible: true
                },
                chartType: 'LineChart',

              }
            });
          }
  }


  // //Warns the user that it has no tags
  presentToastTag() {
    let toast = this.toastCrtl.create({
      message: 'Este utilizador não tem nenhuma tag associada!',
      duration: 3000,
      position: 'bottom',
    });

    toast.present();
  }

  moreInfoTag(tag) {
    this.navCtrl.push(MoreInfoTagPage, { tag: tag });
  }

  searchTag(ev: any) {

  }

  onChangeGroup() {

    for (var i = 0; i < this.charts.length; i++) {
      this.charts[i].options.outros.visible = true
    }

    if (this.selectedGroup == "all") {
      for (var i = 0; i < this.charts.length; i++) {
        this.charts[i].options.outros.visible = false;
      }
    } else {
      for (var i = 0; i < this.charts.length; i++) {
        if (this.selectedGroup == this.charts[i].options.outros.group.group) {
          this.charts[i].options.outros.visible = true;
        }
        console.log(this.charts[i]);
      }
    }
  }

  doRefresh(refresher) {

    setTimeout(() => {
      if (this.selectedGroup == "all") {

        let updatedData = []
        for (let i = 0; i < this.tagsId.length; i++) {
          this.tagService.teste(this.tagsId[i].tagId).subscribe(tagData => {
            updatedData.push(tagData["tagData"]["tagData"])
          })
        }
        
        for (let i = 0; i < updatedData.length; i++) {
          for (let data of updatedData[i]) {
            data[0] = new Date(data[0])
          }
          updatedData[i].unshift(['Dias', 'Indice', { type: 'number', role: 'annotation' }])
        }

        
        for (let i = 0; i < updatedData.length; i++) {
          this.charts[i].data = updatedData[i]
          this.googleCharts.drawChartSelected(this.charts[i]);
        }

        this.event.subscribe('Loaded', (chartLoaded) => {
          this.loaded = chartLoaded;

        })

        
      } else {
        console.log("Update só de um grupo");
      }
      refresher.complete();
    }, 1000);
  }
}

Googlechart Component


import { Directive, ElementRef, Input, OnInit } from '@angular/core';
import { Events } from 'ionic-angular';

declare var google: any;
declare var googleLoaded: any;

@Directive({
    selector: 'google-chart'
})
export class GoogleChartComponent implements OnInit {

    public _element: any;
    public wrapper: any;

    chartLoaded: boolean = false;

    @Input('chartType') public chartType: string;
    @Input('chartOptions') public chartOptions: Object;
    @Input('chartData') public chartData: Object;

    constructor(public element: ElementRef, public events: Events) {
        this._element = this.element.nativeElement;
    }

    ngOnInit() {
        setTimeout(() => {
            google.charts.load('current', { 'packages': ['corechart'] });
            setTimeout(() => {
                google.charts.setOnLoadCallback(this.drawChartLoad());
            }, 1000);
        }, 1000);
    }

    drawChartLoad() {
        this.wrapper = new google.visualization.ChartWrapper({
            chartType: this.chartType,
            dataTable: this.chartData,
            options: this.chartOptions || {},
            containerId: this._element.id
        });
        this.chartLoaded = true;
        this.events.publish('Loaded', this.chartLoaded);
        this.wrapper.draw();
    }

    drawChartSelected(chart?) {
        let loaded = false
        this.wrapper = new google.visualization.ChartWrapper({
            chartType: chart.options.chartType,
            dataTable: chart.data,
            options: chart.options || {},
            containerId: chart.id
        });
        setTimeout(() => {
            this.wrapper.draw();
        }, 1000);
        loaded = true;
        this.events.publish('isLoaded', this.chartLoaded);
    }
}

#4

My problem is in the doRefresh()


#5

Which line exactly is giving you this error? Did you debug it or console.log to understand where exactly things go wrong?

To be honest the code is a bit much to just jump in and understand it - at least for me :wink: It would help if you could trim it down to a minimal code set that just shows the problem.


#6

Sure,
My problem is with the method doRefresh().


  doRefresh(refresher) {

    setTimeout(() => {
      if (this.selectedGroup == "all") {

        let updatedData = []
        for (let i = 0; i < this.tagsId.length; i++) {
          this.tagService.teste(this.tagsId[i].tagId).subscribe(tagData => {
            updatedData.push(tagData["tagData"]["tagData"])
          })
        }
        
        for (let i = 0; i < updatedData.length; i++) {
          for (let data of updatedData[i]) {
            data[0] = new Date(data[0])
          }
          updatedData[i].unshift(['Dias', 'Indice', { type: 'number', role: 'annotation' }])
        }

        
        for (let i = 0; i < updatedData.length; i++) {
          this.charts[i].data = updatedData[i]
          this.googleCharts.drawChartSelected(this.charts[i]);
        }

        this.event.subscribe('Loaded', (chartLoaded) => {
          this.loaded = chartLoaded;

        })

        
      } else {
        console.log("Update só de um grupo");
      }
      refresher.complete();
    }, 1000);
  }

and with this method on GooglechartComponent

 drawChartSelected(chart?) {
        let loaded = false
        this.wrapper = new google.visualization.ChartWrapper({
            chartType: chart.options.chartType,
            dataTable: chart.data,
            options: chart.options || {},
            containerId: chart.id
        });
        setTimeout(() => {
            this.wrapper.draw();
        }, 1000);
        loaded = true;
        this.events.publish('isLoaded', this.chartLoaded);
    }

and it throws this error:

core.es5.js:1085 ERROR Error: The container #3 is not defined.
    at g (polyfills.js:3)
    at gvjs_Z.gvjs_.getContainer (jsapi_compiled_default_module.js:240)
    at gvjs_Z.gvjs_.draw (jsapi_compiled_default_module.js:236)
    at google-chart-component.ts:55
    at t.invokeTask (polyfills.js:3)
    at Object.onInvokeTask (core.es5.js:4136)
    at t.invokeTask (polyfills.js:3)
    at n.runTask (polyfills.js:3)
    at invoke (polyfills.js:3)
    at e (polyfills.js:2)

#7

Yeah but which line is the last one executed successfully in drawChartSelected before that?


#8

The error happens on this line this.wrapper.draw();