6

I am developing a Ionic2 App, using the cordova-plugin-network-information, I am subscribing to the connect and disconnect events from my app.ts and want to be able to pass a reference to my NavController and a Loading component into the subscribe() callback, so whenever the event for a disconnect fires, I can present the user with a Loading overlay on top of the UI. I see that in the callback the reference to the "this" object changes to an object called "SafeSubscriber", which I think is the rxjs typed class for its Observer object, the problem I have here is that I have no way to get those instances available in app.ts to this code inside the callback, using the Chrome DevTools I also wasn't able to find my way out of this context in order to access the App object itself.

Here is my code:

    ngOnInit()
    {
      // Nav Controller:
      this.nav = <NavController>this.app.getComponent('nav');

      // Disconnect Detection
      let disconnectSubscription = Network.onDisconnect().subscribe(() =>
      {
          console.log('Disconnect Detected');
          // Push Loading into nav stack here...!
          // this.nav.present(this.loading);  <- no this object...
      });
    }

This is what I get when querying for the 'this' object inside Chrome DevTools (this is supposed to keep its original context inside a lambda [fat arrow] function is this correct?)

enter image description here

I have tried setting a "that" object before doing the subscription, so that the variable "this" doesn't interfere with the callback "this" scope, it didn't work in this scenario, as 'that' which was declared immediately before the subscribe() (let that: any = this;) was undefined inside of the callback when the disconnect event was fired.

I know that this is not the best place to put code that changes directly the UI, but I see no other place, since what I need here is a global event handler that works by setting this overlay whenever there is no connection detected and the user is viewing certain pages within the app.

I think there should be a very easy and elegant solution to this, but I don't seem to be able to find it. Is there a way to pass a parameter to the subscribe() function? some sort of object with the references I need?

Thanks in advance.

Will de la Vega
  • 536
  • 1
  • 5
  • 17
  • The mistake is somewhere else. `this.nav...` or `this.loading` works fine at this place. Did you check `this.nav` or `this.loading` actually has a value when the `subscribe(...)` callback is called? – Günter Zöchbauer May 09 '16 at 03:38
  • both objects are available outside the callback, problem is inside of the lambda function as it seems to execute at any point of the app lifetime and I think the app.ts scope is long gone. I am not totally positive about this, but in the chrome dev tools the environment seems to be pretty isolated. My tsconfig.json is set to use ES5, would that be the problem? – Will de la Vega May 09 '16 at 13:16
  • The scope is available all the time. I guess it will be pretty hard to provide support without more information, Ideally a Plunker where this can be reproduced and debugged. – Günter Zöchbauer May 09 '16 at 14:16

4 Answers4

1

I'm pretty sure that simple closure should do the trick. Try this:

ngOnInit()
    {
      // Nav Controller:
     var nav = <NavController>this.app.getComponent('nav');

      // Disconnect Detection
      let disconnectSubscription = Network.onDisconnect().subscribe(() =>
      {
          console.log('Disconnect Detected');          
          nav.present(true);  
      });
    }
Toan Nguyen
  • 11,263
  • 5
  • 43
  • 59
  • it should work but i'm having the same issue with context and - amazingly - this doesn't work. it seems they managed to break javascript. – Moika Turns Sep 08 '21 at 17:47
1

I ran into this same problem. I am getting SafeSubscriber in my project as well. However, when I attempted to create a Plunker for it, I was unable to reproduce the problem. That said, the attached plunker does demonstrate that the fat arrow + this behaves as expected. So you should not have to do any that = this style workaround.

Lucas
  • 14,227
  • 9
  • 74
  • 124
  • 1
    This saved me a ton of time! I was hitting this problem when I was passing an explicit function(d) {..} to `subscribe` -- the `this` context would be `SafeSubscriber`. When I switched to `(d) => { .. }` it seemed to provide the right context. I had thought the two were equivalent! – atomic77 Feb 05 '18 at 02:47
1

To pass the component variable objects inside subscribe you have to play with more rxjs operators like combineLatest. Simply create a new Observable of the object you want to pass inside subscribe and make that as an argument to combineLatest. eg.

    // Note: The **of** here is the rxjs of operator to create the observable. 
    combineLatest(
         [
            of(the object you want to pass{Here you will have the this variable}), 
            your API call
         ])
        .pipe(take(1),)
        .subscribe(([yourObject, apiResponse]) => {
            console.log(yourObject + " " + apiResponse);
         });

Here is the reference I found my final answer.

karan patel
  • 537
  • 5
  • 11
0

Karan's pattern worked but this did too, which is a bit simpler (using bind):

    ngOnInit()
    {
      // Nav Controller:
      this.nav = <NavController>this.app.getComponent('nav');

      // Disconnect Detection
      const fn = (() => {
          console.log('Disconnect Detected');
          this.nav.present(this.loading); // 'this' should be set right
      }).bind(this);
      let disconnectSubscription = Network.onDisconnect().subscribe(fn);
    }

Not run it, but the same works for the code I have which follows the same pattern and had the same fault as op describes. Using a closure didn't work, I don't understand why. The caller 'SafeSubscriber' used the call method and set the context to itself as part of that invocation.

Moika Turns
  • 677
  • 11
  • 17