如何使用angular2将数据更改为子组件?

时间:2016-02-23 17:17:19

标签: promise angular

我正在尝试构建绘制图表的angular2组件(使用jquery plot)

import {Component, ElementRef, Input, OnChanges} from 'angular2/core';

@Component({
  selector: 'flot',
  template: `<div>loading</div>`
})

export class FlotCmp  implements OnChanges{

  private width = '100%';
  private height = 220;
  static chosenInitialized = false;

  @Input() private  options: any;
  @Input() private  dataset:any;
  @Input() private  width:string;
  @Input() private  height:string;


  constructor(public el: ElementRef) {}



  ngOnChanges() {
      if(!FlotCmp.chosenInitialized) {
        let plotArea = $(this.el.nativeElement).find('div').empty();
        plotArea.css({
            width: this.width, 
            height: this.height
        });

        $.plot( plotArea, this.dataset, this.options);    
        FlotCmp.chosenInitialized = true;
      }
  } 
}  

组件获取图表&#34;数据&#34; property作为输入参数:

      <flot  [options]="splineOptions" [dataset]="dataset" height="250px" width="100%"></flot>

到目前为止,我设法使其工作只要&#34;数据集&#34;是静态变量。

 this.dataset = [{label: "line1",color:"blue",data:[[1, 130], [3, 80], [4, 160], [5, 159], [12, 350]]}];

我的问题是当数据作为承诺时使它工作:

export class App implements OnInit {

  private dataset:any;
  public entries;  
  getEntries() {
    this._flotService.getFlotEntries().then(
                       entries => this.dataset[0].data = entries,
                       error =>  this.errorMessage = <any>error);
  } 

  ngOnInit() {  
    this.getEntries() 
  } 



  constructor(private _flotService:FlotService) {
    this.name = 'Angular2'
    this.splineOptions = {
            series: {
                lines: { show: true },
                points: {
                    radius: 3,
                    show: true
                }
            }
    };
    this.dataset = [{label: "line1",color:"blue",data:null]}];

  }

}

由于某种原因,数据更改无法投射到&#34; flot&#34;成分

此处链接指向plunk

请帮忙

2 个答案:

答案 0 :(得分:2)

问题是

entries => this.dataset[0].data = entries,

因为只更改了绑定值的内部状态,并且Angular2更改检测不会仅查看内容中的值或引用本身。

解决方法是创建具有相同内容的新数组

this._flotService.getFlotEntries().then(
                   entries => {
                     this.dataset[0].data = entries;
                     this.dataset = this.dataset.slice();
                   },

在您的情况下,可以使用其他事件通知子组件更新已经发生。

答案 1 :(得分:1)

除了Günter的回答,另一个选择是在ngDoCheck()内实现自己的变更检测,当您的数据从服务器返回时将会调用它:

ngDoCheck() {
   if(this.dataset[0].data !== null && !this.dataPlotted) {
      console.log('plotting data');
      let plotArea = $(this.el.nativeElement).find('div').empty();
      $.plot( plotArea, this.dataset, this.options);    
      this.dataPlotted = true;
   }
}

我觉得这是一种更简洁的方法,因为我们不必为了满足/触发角度变化检测而以特定的方式编写代码。但唉,它的效率较低。 (当发生这种情况时,我讨厌它!)

此外,ngOnChanges()中的代码可以移至ngOnInit()

Plunker

正如Günter已经提到的,ngOnChanges()未被调用,因为填写数据时dataset数组引用不会更改。因此Angular不认为任何输入属性发生了变化,因此不会调用ngOnChanges()。无论是否有任何输入属性更改,ngDoCheck()始终会被调用每个更改检测周期。

另一个选择是在父组件中使用@ViewChild(FlotCmp),它将获得对FlotCmp的引用。然后,父级可以使用该引用在drawPlot()上调用某个方法(例如FlotCmp),以在数据到达时绘制/更新绘图。

drawPlot(dataset) {
  console.log('plotting data', dataset);
  let plotArea = $(this.el.nativeElement).find('div').empty();
  $.plot( plotArea, dataset, this.options);
  this.dataset = dataset;
}  

Plunker

这比ngDoCheck()效率更高,并且它没有我在上面用ngOnChanges()方法描述的问题。

但是,如果我使用这种方法,我会稍微修改代码,因为我不喜欢dataset当前是一个输​​入属性,但是drawPlot()获取传入的数据通过函数参数。