Angular 2 - 模型更改后视图未更新

14 浏览
0 Comments

Angular 2 - 模型更改后视图未更新

我有一个简单的组件,每隔几秒调用一次REST api并接收一些JSON数据。通过我的日志语句和网络流量,我可以看到返回的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;
    constructor(private recentDetectionService: RecentDetectionService) {
        this.recentDetections = new Array();
    }
    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());
    }
}

而我的视图如下:

    

Recently detected

 

Recently detected devices

 

Id Vendor Time Mac
{{detected.broadcastId}} {{detected.vendor}} {{detected.timeStamp | date:'yyyy-MM-dd HH:mm:ss'}} {{detected.macAddress}}

 

通过console.log(this.recentDetections[0].macAddress)的结果,我可以看到recentDetections对象正在更新,但视图中的表格除非重新加载页面,否则永远不会改变。

我正在努力找到我到底做错了什么。 有人可以帮忙吗?

admin 更改状态以发布 2023年5月22日
0
0 Comments

这原本是@Mark Rajcok在评论中的一个答案, 但是我想把它放在这里作为一个已经测试并作为使用ChangeDetectorRef 的解决方案, 我认为这是一个不错的观点:

另一个选择是注入ChangeDetectorRef并调用cdRef.detectChanges()而不是zone.run()。这可能更有效率,因为它不会像zone.run()一样在整个组件树上运行变更检测。- Mark Rajcok

所以代码必须像这样:

import {Component, OnInit, ChangeDetectorRef} from 'angular2/core';
export class RecentDetectionComponent implements OnInit {
    recentDetections: Array;
    constructor(private cdRef: ChangeDetectorRef, // <== added
                private recentDetectionService: RecentDetectionService) {
        this.recentDetections = new Array();
    }
    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()subscibe内可能会导致问题Attempt to use a destroyed view: detectChanges

要解决这个问题,你需要在销毁组件之前取消订阅,所以完整的代码应该像这样:

import {Component, OnInit, ChangeDetectorRef, OnDestroy} from 'angular2/core';
export class RecentDetectionComponent implements OnInit, OnDestroy {
    recentDetections: Array;
    private timerObserver: Subscription;
    constructor(private cdRef: ChangeDetectorRef, // <== added
                private recentDetectionService: RecentDetectionService) {
        this.recentDetections = new Array();
    }
    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();
    }
}

0
0 Comments

可能是你的服务中的代码不小心跑出了Angular的zone,导致变更检测不能正常工作。应该采用以下方法处理:

import {Component, OnInit, NgZone} from 'angular2/core';
export class RecentDetectionComponent implements OnInit {
    recentDetections: Array;
    constructor(private zone:NgZone, // <== added
        private recentDetectionService: RecentDetectionService) {
        this.recentDetections = new Array();
    }
    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());
    }
}

如需其他手动触发变更检测的方法,请查看在Angular中手动触发变更检测

其他触发变更检测的方法包括:

ChangeDetectorRef.detectChanges()

立即针对当前组件和它的子组件运行变更检测

ChangeDetectorRef.markForCheck()

在下次Angular运行变更检测时包括当前组件

ApplicationRef.tick()

对整个应用运行变更检测

0