【问题标题】:Angular2 component view not updating when variable changes变量更改时Angular2组件视图不更新
【发布时间】:2016-08-08 22:29:16
【问题描述】:

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

它初始化很好,进度也很好地传递给它,但是模板没有用新值更新。

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

其他地方

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

  onProgress(progress: number) {
    this.progressBar.onProgress(progress*100);
  }

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

【问题讨论】:

  • 如果您更新您的问题以向我展示如何调用 onProgress,我可能会让我的回答对您更有帮助 - 我怀疑这里使用了更深层次的反模式。
  • 添加了 onProgress 部分。它是通过我订阅的 xhr onprogress 检索到的。
  • 我是对的 :-) 请稍等,我会更新

标签: data-binding angular components


【解决方案1】:

你这样做的方式与框架背道而驰,会导致很多人哭泣和咬牙切齿。

现在,您手动订阅一个 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 ...
}

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

但是你现在对 angular 撒了谎——就目前而言,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
  }

}

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

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

这就是它所需要的:栏的宽度和上面的文本现在都将自动更新以反映从您的httpFileService 发出的值,并且您不必编写一行 使之发生的命令式代码。

【讨论】:

  • 我实现了上述,但我面临的问题是进度条没有自动更新。但是,如果我单击该栏,则效果很好。该栏将显示来自可观察对象的当前值。有什么想法吗?
  • @Hammer 你描述的是一个变化检测问题
  • 是的。同意,但是我将代码与您在此处共享的代码进行了比较,没有任何线索..我将代码粘贴在这里,如果您能帮忙看一下,不胜感激?谢了。 stackoverflow.com/questions/37046757/…
猜你喜欢
  • 1970-01-01
  • 2023-03-17
  • 2016-04-02
  • 2016-12-18
  • 2016-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多