Running an observable into a zone.js
Asked Answered
S

3

11

I have a GPS plugin providing locations out of an angular zone. The changes are therefore not detected by angular and the view keeps stuck with the same values.

Of course, I could subscribe to this observable from the controller and do something like that.

$mySourceOutOfZone.subscribe((value)=>{
            this.zone.run(() => {
                this.value = value;
            });
})

And the view will simply use the value like:

<span>{{value}}</span>

But I would like to avoid having to subscribe to the controller and using the imperative style way.

How could I have this observable to run inside an angular zone?

Snowshoe answered 19/6, 2018 at 12:36 Comment(0)
S
6

It seems there is a plugin dedicated to rxjs and zones:

The zone can be bound to any rxjs stream using

.enterZone(this.ngZone)

or using the pipe operator:

.pipe(enterZone(this.ngZone))
Snowshoe answered 19/6, 2018 at 12:42 Comment(0)
G
22

When using RxJs 6+, a custom pipe operator can wrap the observable's behavior in a zone.run() for the specified zone.

import { Observable, OperatorFunction } from 'rxjs';
import { NgZone } from '@angular/core';

export function runInZone<T>(zone: NgZone): OperatorFunction<T, T> {
  return (source) => {
    return new Observable(observer => {
      const onNext = (value: T) => zone.run(() => observer.next(value));
      const onError = (e: any) => zone.run(() => observer.error(e));
      const onComplete = () => zone.run(() => observer.complete());
      return source.subscribe(onNext, onError, onComplete);
    });
  };
}

The operator can then be added to an observable, letting you be explicit about when to change zone contexts.

return exampleObservable.pipe(
  runInZone(this.zone)
);
Geese answered 11/8, 2019 at 18:2 Comment(2)
No dependency required, still accurate and up to date, worked perfectly. Thank you.Wasteful
For RxJS 7 i changed this to: return (source) => { return new Observable(observer => { return source.subscribe({ next: (value: T) => zone.run(() => observer.next(value)), error: (e: any) => zone.run(() => observer.error(e)), complete: () => zone.run(() => observer.complete()) }); }); };Inexecution
S
6

It seems there is a plugin dedicated to rxjs and zones:

The zone can be bound to any rxjs stream using

.enterZone(this.ngZone)

or using the pipe operator:

.pipe(enterZone(this.ngZone))
Snowshoe answered 19/6, 2018 at 12:42 Comment(0)
B
0

You can also try this patch. Add this line inside polyfills.ts after import zone.js.

import `zone.js/dist/zone-patch-rxjs`;

So subscription callback will run in the zone when it call .subscribe.

Bald answered 19/6, 2018 at 16:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.