【问题标题】:how to project data change into child component with angular2?如何使用 angular2 将数据更改投影到子组件中?
【发布时间】:2016-02-24 07:43:38
【问题描述】:

我正在尝试构建绘制图表的 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;
      }
  } 
}  

组件获取图表“数据”属性作为输入参数:

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

到目前为止,只要“数据集”是静态变量,我就设法让它工作。

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

  }

}

由于某种原因,数据更改无法投射到“浮动”组件

这里是plunk的链接

请帮忙

【问题讨论】:

    标签: promise angular


    【解决方案1】:

    问题是

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

    因为只有绑定值的内部状态发生了变化,而 Angular2 变化检测不会只观察值或引用本身的内容。

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

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

    在您的情况下,可能会发生一个额外的事件,通知子组件发生了更新。

    【讨论】:

      【解决方案2】:

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

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

      另外,您在ngOnChanges() 中的代码可以移动到ngOnInit()

      Plunker

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


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

      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() 获取通过函数参数传入的数据.

      【讨论】:

      • 非常感谢您这么详细非常清晰的解释
      猜你喜欢
      • 2015-11-19
      • 2020-07-25
      • 2023-01-04
      • 2016-02-29
      • 2012-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多