变量更改时Angular2组件视图不会更新

Dre*_*nes 5 data-binding components angular

我有一个简单的组件,只是呈现进度条.

它初始化很好,进度很好,但模板没有使用新值更新.

import {Component} from 'angular2/core';

@Component({
  selector : 'progress-bar',
  template : `
    <div class="progress-container">
      <div>{{currentProgress}}</div>
      <div [style.width.%]="currentProgress" class="progress"></div>
    </div>
  `,
  styles: [
    '.progress-container {width: 100%; height: 5px}',
    '.progress {background-color: #8BC34A; height:5px}'
  ]
})

export class ProgressBar {
  currentProgress: number;

  constructor() {
    this.currentProgress = 0;
  }

  onProgress(progress: number) {
    console.log(progress) //consoles correct percentages
    this.currentProgress = progress;
  }

  reset() {
    console.log(this.currentProgress) //is 100
    this.currentProgress = 0;
  }
}
~
Run Code Online (Sandbox Code Playgroud)

别处

  ngOnInit() {
    this.httpFileService.progress$.subscribe((progress: number) => this.onProgress(progress));
  }

  onProgress(progress: number) {
    this.progressBar.onProgress(progress*100);
  }
Run Code Online (Sandbox Code Playgroud)

我觉得我错过了一些非常有用的东西.

dre*_*ore 11

你正在以一种与框架相对立的方式来解决这个问题,并且会导致更多的嚎叫和咬牙切齿.

现在,您手动订阅一个observable - httpFileService.progress$然后手动更新子ProgressBar组件上的属性,绕过angular的更改检测机制 - 这就是UI未更新的原因.您可以在设置此属性后手动触发更改检测,并且UI将按预期更新 - 但同样,您将反对该框架,所以让我们看看如何使用它:

我假设"其他地方"是您ProgressBar组件的父级- 让我们称之为ElsewhereComponent.

@Component({
  selector: 'elsewhere',
  directives: [ProgressBar],
  template: ` 
    <div>
      <progress-bar [currentProgress]="httpFileService.progress$"></progress-bar>
    </div>  
   `
})
class ElsewhereComponent { 
  // you can remove the ngOnInit and onProgress functions you posted
  // you also don't need a reference to the child ProgressBar component
  // ... whatever else you have in this class ...
}
Run Code Online (Sandbox Code Playgroud)

这里要注意的最重要的事情是增加了[currentProgress]的上progress-bar部分:这是告诉角度,有一个名为输入属性currentProgress应绑定到该组件上httpFileService.progress$.

但是你现在已经撒谎了 - 就像它所说的那样,ProgressBar根本没有输入,当它试图将这个不存在的属性绑定到给定值时,angular会告诉你它.所以我们需要添加input属性,首选的方法是使用Input()装饰器:

@Component({
  selector : 'progress-bar',
  pipes: [AsyncPipe]  //import this from angular2/core
  template : `
    <div class="progress-container">
      <div>{{currentProgress | async}}</div>
      <div [style.width.%]="currentProgress | async" class="progress"></div>
    </div>
  `
})
export class ProgressBar {
  @Input() currentProgress: Observable<number>;
  ...
  constructor(){ 
     // remove the line you have in here now
  }

}
Run Code Online (Sandbox Code Playgroud)

这里有两个关键的区别需要注意:首先,@Input()告诉angular currentProgress是一个输入属性.我们还将该属性的类型更改numberObservable<number>- 这不是绝对必要的,但它很有用,因为它允许第二个关键区别:

AsyncPipe已添加到组件中pipes,并在其两个模板绑定中使用currentProgress.这很有用,因为它告诉angular处理订阅Observable的所有脏工作,并在每次发出新值时更新UI.

这就是所需要的:条形图的宽度和它上面的文本现在都会自动更新以反映从您发出的值httpFileService,并且您不必编写一行命令性代码来实现它.