How can I "monkey patch" observed for Zone.js?

I am creating an Angular 2 component, and Angular change detection does not work for me when using a specific Observable pattern. It looks something like this:

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); 

Then in my template:

 <h1>Ready to Log In: {{readyToLogin$ | async}}</h1> <h1>Logged In: {{isLoggedIn$ | async}}</h1> 

Since readyToLogin$ Observable is based on a synchronous set of operations that occur in response to http.get() (where Angular “promises a monkey” to make sure it knows when to detect changes), “Ready to log in” to true switches at the appropriate time.

However, since processSignInResponse() creates a Promise<> , everything that subscribes to the result of flatMap happens asynchronously with the HTTP request completion event. Therefore, it requires manual intervention to notify my component area of ​​the need to verify changes.

How can I wrap observable signInResponse$ in a way that NgZone knows to detect changes after any subscriptions have been allowed?

Update

Brandon's answer worked until I upgraded to RC5, after which everything stopped working. It turns out a third-party library in which I used borked Zone.js. After it was allowed, there was no need to use a workaround at all - the monkey’s built-in patch would just work!

+7
angular rxjs zonejs
source share
2 answers

You can create a new observeOnZone statement that can be used to "patch monkeys" on any observable. Something like:

 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); }); }; 

And use it like this:

 this.isLoggedIn$ = signinResponse$.map(() => true).startWith(false).observeOnZone(zone); 
+7
source share

You can force the code into the corner zone using zone.run()

 constructor(private zone:NgZone) {} someMethod() { signinResponse$.subscribe(value => { zone.run(() => doSomething()); }); } 
+2
source share

All Articles