Search code examples
angularcomponentsobservablezone

Angular 2 : what make a service to be "Outside" angular zone?


After having same issues as many people on StackOverflow i didn't manage to understand what is an "Outside angular zone" Service ?

I've checks all existing questions around this subject, and it's exactly why i needer to ask this one :

Code Example in any component with default ChangeDetectionStrategy : (considering this.value referenced in view)

this.myService.method().subscribe(e => {
    this.value = e;
  });

Is the given service is not "Outside angular zone", the view is refreshed, on the other hand, if it's "Outside angular zone", the view is not refreshed, unless we call ChangeDetectorRef.detectChanges().

So the question is : what the condition to know if a service is Inside or Outside "Angular Zone" ?


Solution

  • The code you want is NgZone.isInAngularZone(). This will tell you whether or not it's executing there.

    Source: hours of banging my head against the wall reading Angular docs before writing this.

    Additionally, you can inject NgZone into your service and try using this.ngZone.run(() => yourSubscriberCallback()) which should help, though I'm having very mixed results attempting this.

    EDIT: Okay, I managed to get my stuff working, let's see if it helps you.

    In my case I was using a third party library that included a listener for changes. I was using an RXJS BehaviorSubject to propagate these changes to various components via a service, but the changes weren't being picked up.

    It turns out that this was because the method I used in the listener was executing outside of the AngularZone.

    At first I was doing this:

    export class Service {
    
      public BehaviorSubject<Thing> thingSubject = new BehaviorSubject<Thing>(new Thing());
    
      constructor(private ngZone:NgZone) {
        thirdPartyLibrary.listen(ngZone.run(() => myCallback.bind(_this)));
      }
    
      ...
    
    }
    

    And myCallback was doing:

    myCallback(thing) {
      this.thingSubject.next(thing);
    }
    

    Turns out this didn't seem to execute within the Angular Zone correctly. I changed my code to this though and it worked:

    export class Service {
    
      public BehaviorSubject<Thing> thingSubject = new BehaviorSubject<Thing>(new Thing());
    
      constructor(private ngZone:NgZone) {
        thirdPartyLibrary.listen(myCallback.bind(_this));
      }
    
      myCallback(thing) {
        this.ngZone.run(() => this.thingSubject.next(thing));
      }
    
    }
    

    After doing that all my subscribers received the message within the Angular Zone and triggered the expected updates.