I've been trying to set up a network plugin as a service on an app to tell whether there's internet or not.
In my example I've set up two components:
- HOME component with the network listener implemented directly in it and
- TEST component that subscribes to an BehaviourSubject observable in networkService
My problem is when trying to destroy the components as I navigate from one to the other. The component where the app is loaded never gets destroyed. Even if I implement something like @HostListener('window:beforeunload') on top of ngOnDestroy().
I have implemented ngOnDestroy on both components to either remove the listener or unsubscribe to the networkServices's observable respectively.
I noticed that if I refresh the app on say Home:
- I navigate to TEST and HOME.ngOnDestroy() does NOT get called.
- When I navigate back from TEST to HOME, TEST.ngOnDestroy() gets called.
If I refresh the app on TEST the same behaviour happens but reversed
- I navigate to HOME and TEST.ngOnDestroy() does NOT get called.
- When I navigate back from HOME to TEST, TEST.ngOnDestroy() gets called.
I've uploaded the project to a public git just in case: https://github.com/jjgl/ionicNetworkCapacitorTests/
but here are the main bits:
HOME
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Plugins, NetworkStatus, PluginListenerHandle } from '@capacitor/core';
const { Network } = Plugins;
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage implements OnInit, OnDestroy {
networkStatus: NetworkStatus;
networkListenerHome: PluginListenerHandle;
async ngOnInit() {
this.networkListenerHome = Network.addListener('networkStatusChange', (status) => {
console.log("Home Page Network status changed", status);
this.networkStatus = status;
});
this.networkStatus = await Network.getStatus();
}
ngOnDestroy() {
console.log('home destroyed')
this.networkListenerHome.remove();
}
}
TEST
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { ConnectionStatus, NetworkService } from 'src/app/services/network.service';
@Component({
selector: 'app-test-page',
templateUrl: './test-page.page.html',
styleUrls: ['./test-page.page.scss'],
})
export class TestPagePage implements OnInit, OnDestroy {
subscription : Subscription
private statusOnline : boolean;
constructor(private networkService: NetworkService) {}
async ngOnInit() {
console.log('hola')
this.subscription = this.networkService.onNetworkChange().subscribe((status: ConnectionStatus) => {
this.statusOnline = status == ConnectionStatus.Online ? true : false;
console.log('network change, status:', status);
})
}
ngOnDestroy() {
console.log('test destroyed')
this.subscription.unsubscribe()
}
}
Network Service
import { Injectable, OnDestroy } from '@angular/core';
import { Plugins, NetworkStatus, PluginListenerHandle } from '@capacitor/core';
import { BehaviorSubject, Observable } from 'rxjs';
const { Network } = Plugins;
export enum ConnectionStatus {
Online,
Offline
}
@Injectable({
providedIn: 'root'
})
export class NetworkService implements OnDestroy {
private netStatus: BehaviorSubject<ConnectionStatus> = new BehaviorSubject(ConnectionStatus.Offline);
networkStatus: NetworkStatus;
networkListener: PluginListenerHandle;
constructor() {
this.networkListener = Network.addListener('networkStatusChange', (status) => {
console.log("Service Network status changed", status);
this.networkStatus = status;
let auxStatus = status && status.connected ? ConnectionStatus.Online : ConnectionStatus.Offline;
this.netStatus.next(auxStatus)
});
this.initialState()
}
private async initialState(){
this.networkStatus = await Network.getStatus();
let auxStatus = this.networkStatus && this.networkStatus.connected ? ConnectionStatus.Online : ConnectionStatus.Offline;
this.netStatus.next(auxStatus)
}
public onNetworkChange(): Observable<ConnectionStatus> {
return this.netStatus.asObservable();
}
public getCurrentNetworkStatus(): ConnectionStatus {
return this.netStatus.getValue();
}
ngOnDestroy(): void {
console.log('services destroyed')
this.networkListener.remove();
}
}
Needless to say I'm new to Angular so feel free to point out other things too, all comments are welcome.
PS: I've implemented ngOnDestroy on the networkService, but I'm not calling it from TEST as the service doesn't get reinstantiated when navigating back to TEST after TEST.ngOnDestroy gets called the first time.
You cannot use Angular lifecycle in services. Use it inside components only.
Please call
Network.addListener
into app.component.ts.app.component.ts
is a root singleton component, so it's neither destroyed nor refreshed until you refresh the browser tab. Now you can use the netstatus in NetworkService inside any component like you are already doing.