我正在创建一个Angular 2组件,当使用某个Observable模式时,Angular的变化检测对我来说并不适用。它看起来像这样:
let getResult$ = this.http.get('/api/identity-settings');
let manager$ = getResult$
.map((response) => /* -- create manager object -- */);
let signinResponse$ = manager$
.flatMap(manager => manager.processSigninResponse());
this.readyToLogin$ = manager$.map(() => true).startWith(false);
this.isLoggedIn$ = signinResponse$.map(() => true).startWith(false);
然后在我的模板中:
<h1>Ready to Log In: {{readyToLogin$ | async}}</h1>
<h1>Logged In: {{isLoggedIn$ | async}}</h1>
由于readyToLogin$
Observable是基于响应http.get()
而发生的同步操作集(Angular&#34; monkey patches&#34;以确保它知道何时需要检测变化),&#34;准备登录&#34;消息在适当的时间切换到true
。
但是,由于processSignInResponse()
生成Promise<>
,因此订阅flatMap
结果的任何内容都与http请求的完成事件异步发生。因此,它需要手动干预以通知我的组件区域需要检查更改。
如何以signInResponse$
知道在任何订阅解析后检测更改的方式包装NgZone
observable?
布兰登的答案一直有效,直到我更新到RC5,此时事情再次停止工作。结果是the 3rd-party library I was using borked Zone.js。一旦解决了这个问题,就根本不需要使用解决方法 - 内置的猴子补丁工作正常!
答案 0 :(得分:7)
您可以创建一个新的observeOnZone
运算符,该运算符可用于&#34; monkey patch&#34;任何可观察的。类似的东西:
Rx.Observable.prototype.observeOnZone = function (zone) {
return Observable.create(observer => {
var onNext = (value) => zone.run(() => observer.next(value));
var onError = (e) => zone.run(() => observer.error(e));
var onComplete = () => zone.run(() => observer.complete());
return this.subscribe(onNext, onError, onComplete);
});
};
并像这样使用它:
this.isLoggedIn$ = signinResponse$.map(() => true).startWith(false).observeOnZone(zone);
答案 1 :(得分:5)
对于带有pipable运算符的RxJs 6:
private runInZone(zone) {
return function mySimpleOperatorImplementation(source) {
return Observable.create(observer => {
const onNext = (value) => zone.run(() => observer.next(value));
const onError = (e) => zone.run(() => observer.error(e));
const onComplete = () => zone.run(() => observer.complete());
return source.subscribe(onNext, onError, onComplete);
});
};
}
用法:
$someObservable.pipe(runInZone(zone));
答案 2 :(得分:1)
您可以使用zone.run()
constructor(private zone:NgZone) {}
someMethod() {
signinResponse$.subscribe(value => {
zone.run(() => doSomething());
});
}