angular度2 – 查看模型更改后不更新
我有一个简单的组件每隔几秒调用一次REST API,并接收一些JSON数据。 我可以从我的日志语句和networkingstream量中看到正在返回的JSON数据正在改变,并且我的模型正在更新,但是视图没有改变。
我的组件看起来像:
import {Component, OnInit} from 'angular2/core'; import {RecentDetectionService} from '../services/recentdetection.service'; import {RecentDetection} from '../model/recentdetection'; import {Observable} from 'rxjs/Rx'; @Component({ selector: 'recent-detections', templateUrl: '/app/components/recentdetection.template.html', providers: [RecentDetectionService] }) export class RecentDetectionComponent implements OnInit { recentDetections: Array<RecentDetection>; constructor(private recentDetectionService: RecentDetectionService) { this.recentDetections = new Array<RecentDetection>(); } getRecentDetections(): void { this.recentDetectionService.getJsonFromApi() .subscribe(recent => { this.recentDetections = recent; console.log(this.recentDetections[0].macAddress) }); } ngOnInit() { this.getRecentDetections(); let timer = Observable.timer(2000, 5000); timer.subscribe(() => this.getRecentDetections()); } }
我的观点如下所示:
<div class="panel panel-default"> <!-- Default panel contents --> <div class="panel-heading"><h3>Recently detected</h3></div> <div class="panel-body"> <p>Recently detected devices</p> </div> <!-- Table --> <table class="table" style="table-layout: fixed; word-wrap: break-word;"> <thead> <tr> <th>Id</th> <th>Vendor</th> <th>Time</th> <th>Mac</th> </tr> </thead> <tbody > <tr *ngFor="#detected of recentDetections"> <td>{{detected.broadcastId}}</td> <td>{{detected.vendor}}</td> <td>{{detected.timeStamp | date:'yyyy-MM-dd HH:mm:ss'}}</td> <td>{{detected.macAddress}}</td> </tr> </tbody> </table> </div>
我可以从console.log(this.recentDetections[0].macAddress)
的结果中看到recentDetections对象正在被更新,但是视图中的表不会改变,除非我重新加载页面。
我很努力地看到我在这里做错了什么。 谁能帮忙?
可能是你的服务中的代码以某种方式脱离了Angulars区域。 这打破了变化检测。 这应该工作:
import {Component, OnInit, NgZone} from 'angular2/core'; export class RecentDetectionComponent implements OnInit { recentDetections: Array<RecentDetection>; constructor(private zone:NgZone, // <== added private recentDetectionService: RecentDetectionService) { this.recentDetections = new Array<RecentDetection>(); } getRecentDetections(): void { this.recentDetectionService.getJsonFromApi() .subscribe(recent => { this.zone.run(() => { // <== added this.recentDetections = recent; console.log(this.recentDetections[0].macAddress) }); }); } ngOnInit() { this.getRecentDetections(); let timer = Observable.timer(2000, 5000); timer.subscribe(() => this.getRecentDetections()); } }
有关调用更改检测的其他方法,请参阅手动触发Angular2更改检测
调用变更检测的其他方法是
ChangeDetectorRef.detectChanges()
立即运行对当前组件的变化检测,这是孩子
ChangeDetectorRef.markForCheck()
在下一次Angular运行更改检测时包含当前组件
ApplicationRef.tick()
运行整个应用程序的变化检测
尝试使用@Input() recentDetections: Array<RecentDetection>;
编辑:为什么@Input()
是重要的原因是因为你想要在打字稿/ javascript文件中的值视图(HTML)。 如果使用@Input()
装饰器声明的值发生更改,视图将自动更新。 如果一个@Input()
或者@Output()
修饰器被改变了,一个ngOnChanges
事件将会触发,并且这个视图将会用新的值来更新自己。 你可能会说@Input()
会双向绑定这个值。
search在这个链接上的input:angular度更多信息
编辑:在学习了更多关于Angular 2开发之后,我想到做一个@Input()
真的不是解决scheme,正如在评论中提到的,
@Input()
仅适用于数据从组件外部进行数据绑定(父级绑定数据发生更改)而不是数据从组件内部的代码更改时更改的情况。
如果你看一下@Günter的答案,这是一个更准确和正确的解决scheme。 我仍然在这里保留这个答案,但请按照Günter的答案作为正确的答案。
它原本是在@Mark Rajcok的评论中的答案,但我想把它放在这里作为一个testing和使用ChangeDetectorRef作为解决scheme,我看到一个很好的一点在这里:
另一种方法是注入
cdRef.detectChanges()
并调用cdRef.detectChanges()
而不是zone.run()
。 这可能会更有效,因为它不会像zone.run()
那样在整个组件树上运行变更检测。 Mark Rajcok
所以代码一定是这样的:
import {Component, OnInit, ChangeDetectorRef} from 'angular2/core'; export class RecentDetectionComponent implements OnInit { recentDetections: Array<RecentDetection>; constructor(private cdRef: ChangeDetectorRef, // <== added private recentDetectionService: RecentDetectionService) { this.recentDetections = new Array<RecentDetection>(); } getRecentDetections(): void { this.recentDetectionService.getJsonFromApi() .subscribe(recent => { this.recentDetections = recent; console.log(this.recentDetections[0].macAddress); this.cdRef.detectChanges(); // <== added }); } ngOnInit() { this.getRecentDetections(); let timer = Observable.timer(2000, 5000); timer.subscribe(() => this.getRecentDetections()); } }
编辑 :在.detectChanges()
内使用.detectChanges()
可能导致问题尝试使用销毁视图:detectChanges
要解决它,你需要在销毁组件之前unsubscribe
,所以完整的代码将如下所示:
import {Component, OnInit, ChangeDetectorRef, OnDestroy} from 'angular2/core'; export class RecentDetectionComponent implements OnInit, OnDestroy { recentDetections: Array<RecentDetection>; private timerObserver: Subscription; constructor(private cdRef: ChangeDetectorRef, // <== added private recentDetectionService: RecentDetectionService) { this.recentDetections = new Array<RecentDetection>(); } getRecentDetections(): void { this.recentDetectionService.getJsonFromApi() .subscribe(recent => { this.recentDetections = recent; console.log(this.recentDetections[0].macAddress); this.cdRef.detectChanges(); // <== added }); } ngOnInit() { this.getRecentDetections(); let timer = Observable.timer(2000, 5000); this.timerObserver = timer.subscribe(() => this.getRecentDetections()); } ngOnDestroy() { this.timerObserver.unsubscribe(); } }