ngIf not working with subscribe if I dont use NgZone


#1

I have the following:

.html

<ion-content padding no-bounce>
  <!--Se muestra si no hay conexion a internet.-->
  <div *ngIf="!a">
    <p padding>Es necesario estar conectado a Internet para cargar el listado de centros de urgencias. Por favor, conectese a una red WiFi o active sus datos.</p>
  </div>
</ion-content>

.ts

...
import { Network } from '@ionic-native/network';
...

a: boolean;

constructor(private ngZone: NgZone, public navCtrl: NavController, public network: Network) {
   this.a = true
} 

ionViewDidLoad() {
   this.comprobarConexionInternet();
}

comprobarConexionInternet(): void {
    if (this.network.type === 'none') { 
       this.a = false;

      this.network.onConnect().subscribe(() => {  //nos ponemos a observar si se enciende la conexion a internet (si se activa se entra al interior)
          this.a = true;
      });
    }
  }

If I execute this piece of code, the content from the .html will show if I’m not connected to the Internet when I open the page. But if I start listening for Internet connection doing this.network.onConnect().subscribe(), the variable a will be set to true automatically when I get connected (already tested with console.log), but the message from the .html is still showing.

However, if I replace that piece of code for:

this.network.onConnect().subscribe(() => {  //nos ponemos a observar si se enciende la conexion a internet (si se activa se entra al interior)
        this.ngZone.run(() => {
          this.a = true;
       });
});

It works perfectly. I’d like to know why is this and what causes it.

Thanks.


#2

This seems to be a context difference… But why?
Is it because ionViewDidLoad() is apart from the class?


#3

No, it’s a normal ts and all is within the class, just removed that code from the pasted code.


#4

Could you try something different to understand?

ionViewDidLoad() {
  this.ngZone.run(() => {
    this.comprobarConexionInternet();
  })
}

comprobarConexionInternet(): void {
    if (this.network.type === 'none') { 
       this.a = false;

      this.network.onConnect().subscribe(() => { 
          this.a = true;
      });
    }
  }

#5

My problem isn’t that the code isn’t working.

This works:

this.network.onConnect().subscribe(() => {  //nos ponemos a observar si se enciende la conexion a internet (si se activa se entra al interior)
        this.ngZone.run(() => {
          this.a = true;
       });
});

And this doesn’t work:

comprobarConexionInternet(): void {
    if (this.network.type === 'none') { 
       this.a = false;

      this.network.onConnect().subscribe(() => {  //nos ponemos a observar si se enciende la conexion a internet (si se activa se entra al interior)
          this.a = true;
      });
    }
  }

Using NgZone.run() makes it work.

I just wanna know why. What NgZone.run() does and why it doesn’t work without it.


#6

Yeah, I understood, so please try my code, if it works, it’s just the ionViewDidLoad clear it context when all sync code is executed.
Then your async code is returned in another zone that the Angular view zone.


#7

No, that code doesn’t work.


#8

Have you set breakpoints and stepped through this code?

What is this.network.type when your if block runs?

When you say you tested that a gets set to true with a console.log:

  • Why didn’t you use a breakpoint instead of console.log and actually debug?
  • Where did you put your console.log?

Have you tried creating a local subscription variable and then making sure to unsubscribe from it onDestroy?

Those are the possible issues that come to mind, because ngZone shouldn’t be required here afaik.


#9

I did debug but can’t find out what goes on since everything works as it’s supposed to but it doesn’t work without the Ngzone stuff.

The this.network.type is just the Network plugin, if there is conection (none) it gets into the if and starts listening (waiting) for a conection with the .onChange().subscribe() and when the device is connected to the Internet it gets inside the code from the subscribe.


#10

Okay just wanted to make sure the basics were already tested before digging deeper. So the simple answer is that the network connect observable updates outside of angular zone.

You can see this by just logging out a simple test.

ionViewDidLoad() {
  console.log(`ionViewDidLoad inside angular zone?: ${NgZone.isInAngularZone()}`);

  this.connectSubscription = this.network.onConnect().subscribe(() => {
    console.log(`Subscription inside angular zone?: ${NgZone.isInAngularZone()}`);
  });
}

This will log true for the ionViewDidLoad check, but false for the subscribe check

This is a known issue and there is already a bug opened for it: https://github.com/ionic-team/ionic-native/issues/2202


#11

Normally with .then() instead of .subscribe() will be executed as micro task, and in the current context…


#12

Ah okay, so what NgZone.run() does is execute the code it wraps into the angular context.

I get it now, thanks :smiley: