据我所知,如果您更改“Angular 区域”中的数据,Angular 只会更新视图。您示例中的异步调用不符合此条件。但是如果你愿意,你可以把它放在 Angular zone 中或者使用 rxjs 或者将部分代码提取到一个新的组件中来解决这个问题。我将全部解释:
编辑:似乎并不是所有的解决方案都在起作用。对于大多数用户来说,第一个解决方案“Angular Zone”可以完成这项工作。
1 角区
此服务最常见的用途是在启动由一个或多个异步任务组成的工作时优化性能,这些任务不需要由 Angular 处理 UI 更新或错误处理。这些任务可以通过 runOutsideAngular 启动,如果需要,这些任务可以通过run重新进入 Angular 区域。
https://angular.io/api/core/NgZone
关键部分是“运行”功能。您可以注入 NgZone 并将您的值更新放在 NgZone 对象的运行回调中:
constructor(private ngZone: NgZone ) { }
testVariable: string;
ngOnInit() {
this.testVariable = 'foo';
this.someService.someObservable.subscribe(
() => console.log('success'),
(error) => console.log('error', error),
() => {
this.ngZone.run( () => {
this.testVariable += '-bar';
});
}
);
}
根据这个答案,它会导致整个应用程序检测到更改,而您的 ChangeDetectorRef.detectChanges 方法只会检测到您的组件及其后代中的更改。
2 RxJS
另一种方法是使用rxjs
更新视图。当你第一次订阅ReplaySubject时,它会给你最新的值。A BehaviorSubject基本相同,但允许您定义默认值(在您的示例中有意义,但不一定总是正确的选择)。在这个初始发射之后,它基本上是一个正常的重播主题:
this.testVariable = 'foo';
testEmitter$ = new BehaviorSubject<string>(this.testVariable);
ngOnInit() {
this.someService.someObservable.subscribe(
() => console.log('success'),
(error) => console.log('error', error),
() => {
this.testVariable += '-bar';
this.testEmitter.next(this.testVariable);
}
);
}
在您看来,您可以使用异步管道订阅主题:
{{testEmitter$ | async}}
3 将代码提取到新组件
如果您将字符串提交给另一个组件,它也会被更新。您必须@Input()
在新组件中使用选择器。
所以新组件的代码如下:
@Input() testVariable = '';
并且 testVariable 像以前一样在 HTML 中分配,带有花括号。
在父 HTML 视图中,您可以将父元素的变量传递给子元素:
<app-child [testVariable]="testVariable"></app-child>
这样你就在 Angular 区域。
4 个人喜好
我个人的偏好是使用 rxjs 或者组件方式。使用detectChanges oder NGZone 对我来说感觉更hacky。