简体   繁体   English

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

[英]how to project data change into child component with angular2?

i'm trying to build angular2 component which draws chart (using jquery plot) 我正在尝试构建绘制图表的angular2组件(使用jquery图)

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;
      }
  } 
}  

Component getting chart "data" property as input parameter: 将图表“data”属性作为输入参数的组件:

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

So far i managed to make it work as long as "dataset" is static variable. 到目前为止,只要“dataset”是静态变量,我就设法使其工作。

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

My problem is to make it work when data came as a promise: 我的问题是当数据作为承诺时使其工作:

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]}];

  }

}

For some reason data change cannot project to "flot" component 由于某种原因,数据更改无法投射到“flot”组件

here is link to plunk 这里是plunk的链接

Please help 请帮忙

The problem is 问题是

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

because only the inner state of the bound value is changed and Angular2 change detection doesn't observe the content only the value or reference itself. 因为只有绑定值的内部状态发生了变化,Angular2变化检测才会观察到内容只有值或引用本身。

A workaround would be to create a new array with the same content 解决方法是创建具有相同内容的新阵列

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

In your case an additional event could work that notifies the child component that updates have happended. 在您的情况下,可以使用其他事件通知子组件更新已经发生。

Besides Günter's answer, another option is to implement your own change detection inside ngDoCheck() which will be called when your data comes back from the server: 除了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;
   }
}

I feel this is a cleaner approach, since we don't have to write code a specific way just to satisfy/trigger Angular change detection. 我觉得这是一种更简洁的方法,因为我们不必为了满足/触发角度变化检测而以特定的方式编写代码。 But alas, it is less efficient. 但唉,它的效率较低。 (I hate it when that happens!) (当发生这种情况时,我讨厌它!)

Also, the code you have in ngOnChanges() can be moved to ngOnInit() . 此外,您在ngOnChanges()的代码可以移动到ngOnInit()

Plunker Plunker

As Günter already mentioned, ngOnChanges() isn't called because the dataset array reference doesn't change when you fill in your data. 正如Günter已经提到的那样,不会调用ngOnChanges()因为填充数据时dataset数组引用不会更改。 So Angular doesn't think any input properties changed, so ngOnChanges() isn't called. 因此Angular不认为任何输入属性发生了变化,因此不会调用ngOnChanges() ngDoCheck() is always called every change detection cycle, whether or not there are any input property changes. 无论是否有任何输入属性更改,都会在每个更改检测周期中调用ngDoCheck()


Yet another option is to use @ViewChild(FlotCmp) in the parent component, which will get a reference to FlotCmp . 另一种选择是在父组件中使用@ViewChild(FlotCmp) ,它将获得对FlotCmp的引用。 The parent could then use that reference to call some method, say drawPlot() , on FlotCmp to draw/update the plot when the data arrives. 然后,家长可以使用参考调用一些方法,比如说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 Plunker

This is more efficient than ngDoCheck() , and it doesn't have the issue I described above with the ngOnChanges() approach. 这比ngDoCheck()更有效,它没有我上面用ngOnChanges()方法描述的问题。

However, if I were to use this approach, I would rework the code somewhat, since I don't like how dataset is currently an input property, but then drawPlot() gets the data passed in via a function argument. 但是,如果我使用这种方法,我会稍微重做代码,因为我不喜欢dataset当前是一个输​​入属性,但是drawPlot()获取通过函数参数传入的数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM