变量更改时 Angular2 组件视图不更新
Angular2 component view not updating when variable changes
我有一个只呈现进度条的简单组件。
它初始化正常,进度也很好,但模板没有更新新值。
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);
}
我觉得我缺少了一些非常补救的东西。
你正在以一种违背框架的方式来解决这个问题,并且会导致大量的哀号和咬牙切齿。
现在,您正在手动订阅一个可观察对象 - httpFileService.progress$
- 然后手动更新子 ProgressBar
组件上的 属性,绕过 angular' s 变化检测机制——这就是 UI 没有更新的原因。您 可以 在设置此 属性 后手动触发更改检测,并且 UI 将按预期更新 - 但是同样,您将与框架作对,所以让我们看看如何使用它:
我假设 "elsewhere" 是您的 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()
装饰器:
@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<number>
- 这不是绝对必要的,但它很有用,因为它允许第二个关键差异:
AsyncPipe
已添加到组件的 pipes
,并在其到 currentProgress
的两个模板绑定中使用。这很有用,因为它告诉 angular 处理所有订阅 Observable 和更新 UI 每次发出新值时的脏活。
这就是它所需要的全部内容:栏的宽度和上面的文本现在都会自动更新以反映从 httpFileService
发出的值,而且您不必写一行的
命令式代码来实现它。
我有一个只呈现进度条的简单组件。
它初始化正常,进度也很好,但模板没有更新新值。
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);
}
我觉得我缺少了一些非常补救的东西。
你正在以一种违背框架的方式来解决这个问题,并且会导致大量的哀号和咬牙切齿。
现在,您正在手动订阅一个可观察对象 - httpFileService.progress$
- 然后手动更新子 ProgressBar
组件上的 属性,绕过 angular' s 变化检测机制——这就是 UI 没有更新的原因。您 可以 在设置此 属性 后手动触发更改检测,并且 UI 将按预期更新 - 但是同样,您将与框架作对,所以让我们看看如何使用它:
我假设 "elsewhere" 是您的 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()
装饰器:
@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<number>
- 这不是绝对必要的,但它很有用,因为它允许第二个关键差异:
AsyncPipe
已添加到组件的 pipes
,并在其到 currentProgress
的两个模板绑定中使用。这很有用,因为它告诉 angular 处理所有订阅 Observable 和更新 UI 每次发出新值时的脏活。
这就是它所需要的全部内容:栏的宽度和上面的文本现在都会自动更新以反映从 httpFileService
发出的值,而且您不必写一行的
命令式代码来实现它。