Saurabh Palatkar
Saurabh Palatkar

Reputation: 3384

Not able to update child component view from parent in angular 2

Punkr: Here

I've a child comp chartist.component which I am using for rendering chartist charts

In my parent component app.ts, I am invoking chartist.component twice to render a line chart and a bar chart

In the parent comp, I've buttons to refresh the line chart and bar chart which just changes the data within the data variable which then passed to child comp to render the charts.

My issue is, charts are being updated only once on click of the refresh button. I want to update the charts every time my data object changes.

app.ts (parent comp):

import {Component, NgModule, OnInit, AfterViewInit} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
import {ChartistChart} from './chartist.component'

@Component({
  selector: 'my-app',
  templateUrl: './src/app.html',,
})
export class App implements OnInit, AfterViewInit {
  name:string;
  data: any;
  isFirst:true;
  dataIndex:number;
  allData:any;

  constructor() {
    this.name = 'Angular2'
    this.dataIndex=0;
    this.allData=[{chart data1},{chart data 2}];
  }

   ngOnInit() {  
    this.getAllCharts();
  }

   ngAfterViewInit() {}

  public getAllCharts(){
    this.data= this.allData[this.dataIndex];
    return this.allData[this.dataIndex];
  }

  public updateLineChart(){
    this.isFirst  = !this.isFirst;
    this.dataIndex = this.isFirst?0:1;
    this.data.simpleLineData = this.allData[this.dataIndex].simpleLineData;
    this.data.simpleLineOptions = this.allData[this.dataIndex].simpleLineOptions;
  }

  public updateBarChart(){
    this.isFirst  = !this.isFirst;
    this.dataIndex = this.isFirst?0:1;
    this.data.simpleBarData = this.allData[this.dataIndex].simpleBarData;
    this.data.simpleBarOptions = this.allData[this.dataIndex].simpleBarOptions;
  }
}

@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App, ChartistChart ],
  bootstrap: [ App ]
})
export class AppModule {}

app.html:

<div style="width:100%; height:350px">
    <button (click)="updateLineChart()">Update Line chart</button> DataIndex: {{dataIndex}}
    <chartist-chart *ngIf="data" chartistChartClass="ct-chart" chartistChartType="Line" [chartistChartData]="data['simpleLineData']"
              [chartistChartOptions]="data['simpleLineOptions']">
            </chartist-chart>
    </div>
          <br/>  <br/>    
    <div style="width:100%; height:350px">
    <button (click)="updateBarChart()">Update Bar chart</button> DataIndex: {{dataIndex}}
       <chartist-chart *ngIf="data" chartistChartClass="ct-chart" chartistChartType="Bar" [chartistChartData]="data['simpleBarData']"
              [chartistChartOptions]="data['simpleBarOptions']">
            </chartist-chart>
    </div>

chartist.component.ts (child):

import {
  Component, ViewChild, Input, Output, ElementRef, EventEmitter, ChangeDetectorRef 
} from '@angular/core';



@Component({
  selector: 'chartist-chart',
  templateUrl: './src/chartistChart.html',
  providers: [],
})
export class ChartistChart {

  @Input() chartistChartType: string;
  @Input() chartistChartData: Object;
  @Input() chartistChartOptions: Object;
  @Input() chartistChartResponsive: Object;
  @Input() chartistChartClass: string;
  @Output() onChartReady = new EventEmitter<any>();

  @ViewChild('chartistChart') public _selector: ElementRef;

  private chart;
   constructor(private cdr: ChangeDetectorRef){}

  ngAfterViewInit() {
   console.log('chart init', this.chartistChartData)
    let _self = this;
    _self.chart = new Chartist[_self.chartistChartType](_self._selector.nativeElement,
      _self.chartistChartData,
      _self.chartistChartOptions);

    _self.onChartReady.emit(_self.chart);
    this.cdr.detectChanges();
  }



  ngOnChanges(changes) {
    if (this.chart) {
      console.log('chartistChartData changed: ',this.chartistChartData);
      (<any>this.chart).update(this.chartistChartData, this.chartistChartOptions);
    }
  }

  ngOnDestroy(): void {
    if (this.chart) {
      this.chart.detach();
    }
  }
}

chartistChart.html:

<div #chartistChart class="{{chartistChartClass || ''}}"></div>

Upvotes: 1

Views: 1623

Answers (1)

dfsq
dfsq

Reputation: 193291

All you need to do is manually call this.getAllCharts() on every button click so that this.data is reassigned to new data series:

public updateLineChart() {
  this.dataIndex = this.dataIndex ? 0 : 1;
  this.getAllCharts();
}

public updateBarChart() {
  this.dataIndex = this.dataIndex ? 0 : 1;
  this.getAllCharts();
}

You can also get rid of redundant isFirst flag, dataIndex is enough. And you don't need to set this.data.simpleBarData and this.data.simpleLineData manually too, as it's already passed as props in template.

Demo: https://plnkr.co/edit/1eyTe5WYFAjL9ssRgdiS?p=preview

Upvotes: 1

Related Questions