【发布时间】:2019-07-03 15:06:21
【问题描述】:
我有一个应用程序,其中包含几个组件,每个组件都异步显示不同的数据。我正在使用 routerLink 在不同的组件之间导航。
问题是,如果我当前正在查看组件 B 时组件 A 中的数据发生更改,则当我返回组件 A 时,DOM 不会更新为新数据。(ngFor 列表将继续显示 test1、test2收到的数据。)但是,使用console.log,我可以在开发工具中看到,当我查看组件B时,组件A仍在接收数据。如果收到新数据时我在组件A中,则DOM 已更新,新数据正确显示。
我需要做些什么来确保在导航回组件时刷新 DOM?我想我可能会检测到 NavigationEnd 并将数据分配给它自己。有什么我遗漏的吗?
提前致谢,代码如下:
组件 A
import { Component, OnInit, ChangeDetectionStrategy, NgZone } from '@angular/core';
import { DataService } from '../../services/data.service';
@Component({
selector: 'app-metars',
templateUrl: './metars.component.html',
styleUrls: ['./metars.component.scss'],
changeDetection: ChangeDetectionStrategy.Default
})
export class TestComponent implements OnInit {
public dataArray = ['test1', 'test2'];
constructor(private _dataService: DataService, private zone: NgZone) { }
ngOnInit() {
this._dataService.data$
.subscribe( data => {
this.zone.run(() => {
this.dataArray = data;
console.log(data); // When in Component B, this is still firing in Dev Tools and I can see the new data being pushed.
});
}
);
}
}
组件 A HTML
<ul *ngFor="let data of dataArray">
{{ data }}
</ul>
<br/>
数据服务
export class DataService {
private data: string[] = new Array<string>();
private _dataSource = new Subject<string[]>();
data$ = this._dataSource.asObservable();
constructor(public electronService: ElectronService) {
this.intitalizeIPCs();
}
intitalizeIPCs() {
this.electronService.ipcRenderer.on('receive-data', (event, arg) => {
console.log('received data');
this.data = arg;
this._dataSource.next(this.data);
});
}
App.component.html
<app-nav></app-nav>
<div class="content">
<router-outlet></router-outlet>
</div>
编辑 - 代码解决方案
接受的答案如下。正确的实现是通过使用异步管道。切换到异步管道后,我继续遇到一个问题,如果服务中的数据发生更改,组件在重新导航到它之前不会看到更改。通过将其封装在 NgZone 中解决了该问题。工作代码如下:
服务:
import { Injectable, NgZone } from '@angular/core';
import { ElectronService } from '../providers/electron.service';
import { Observable, BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class DataService {
private _data: BehaviorSubject<Array<string>> = new BehaviorSubject([]);
public readonly data: Observable<Array<string>> = this._data.asObservable(); // Access this directly using async pipe.
constructor(public electronService: ElectronService, private zone: NgZone) {
this.intitalizeIPCs();
}
intitalizeIPCs() {
this.electronService.ipcRenderer.on('receive-data', (event, arg) => {
this.zone.run(() => {
this._data.next( arg );
});
});
}
}
组件:
import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core';
import { DataService } from '../../services/metar.service';
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.scss'],
changeDetection: ChangeDetectionStrategy.Default
})
export class ExampleComponent implements OnInit {
constructor(private _dataService: DataService) { }
ngOnInit() {
}
}
HTML
<ul *ngFor="let metar of _metarService.metars | async">
{{ metar }}
</ul>
【问题讨论】: