Hi everyone,
recently I faced a problem with the Ionic Network library.
When I tried to change the UI on a network type change (connection or disconnection) the code is run but the UI does not change at all …
After some headaches, some strange logs ([…] chages outside Angular zone […]), and some Google searches … I found something.
It seems the Ionic Network library is run outside the Angular Zone (I’m quite noob with Angular, so at first I did not know what it meant …) even if this library is specified to work with Angular … (@ionic/network/ngx) …
So I think it is nice to share my method (maybe not the best, but it works ^^).
Step 1 : Creation of a pipe to run observable in the Angular zone
src/app/services/observable-util.service.ts
import {NgZone} from '@angular/core';
import {Observable, OperatorFunction} from 'rxjs';
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);
});
};
}
Step 2 : Wrapping Ionic Network in a Service with «runInZone» pipe
src/app/services/network.service.ts
import {Injectable, NgZone} from '@angular/core';
import {Network} from '@ionic-native/network/ngx';
import {Observable} from 'rxjs';
import {runInZone} from './utils/observable-util.service';
/**
* Network service in Angular zone
*/
@Injectable({
providedIn: 'root'
})
export class NetworkService {
constructor(private network: Network, private zone: NgZone) { }
get Connection(): {
UNKNOWN: string;
ETHERNET: string;
WIFI: string;
CELL_2G: string;
CELL_3G: string;
CELL_4G: string;
CELL: string;
NONE: string;
} {
return this.network.Connection;
}
/**
* Network type
*/
get type(): string {
return this.network.type;
}
/**
* Returns an observable to watch connection changes
*/
onChange(): Observable<any> {
return this.network.onChange().pipe(runInZone(this.zone));
}
/**
* Get notified when the device goes offline
*/
onDisconnect(): Observable<any> {
return this.network.onDisconnect().pipe(runInZone(this.zone));
}
/**
* Get notified when the device goes online
*/
onConnect(): Observable<any> {
return this.network.onConnect().pipe(runInZone(this.zone));
}
}
Step 3 : Use the new network service in place of Ionic Network
For example, trigger an ngrx redux store action
[…]
import {NetworkService} from './services/network.service';
@Component([…])
export class AppComponent implements OnInit {
constructor(
[…]
private store: Store<RootStoreState.State>,
private network: NetworkService,
[…]
) {}
[…]
ngOnInit() {
this.network.onDisconnect().subscribe(() => this.store.dispatch(new ConnectionStatusStoreActions.Disconnect()));
this.network.onConnect().subscribe(() => this.store.dispatch(new ConnectionStatusStoreActions.Connect({network: this.network.type})));
}
[…]
}
Step 5 : The UI is refreshed on connection changes
You can chill and breath ^^