Stefan Blattmann Stefan Blattmann - 1 month ago 21
AngularJS Question

Monitoring Online and Offline States in an Ionic Application

I want to monitor in real time if a user's device is online or offline.
I basically use the info from this site: http://www.joshmorony.com/monitoring-online-and-offline-states-in-an-ionic-application/

I was "upgrading" the code a bit but I still have problems to receive real time network state changes. In my factory is a function called

startWatching()
which works awesome - anytime inside the factory and after I access it the first time.

My question: How can I access the changes of the network state inside my controller in real time? I need to show the user some info every time his device is offline.

My controller:

// ### News ###
var newsCtrl = function ($scope, $http, $ionicLoading, PostService, BookMarkService, ConnectivityMonitor) {
console.log('newsCtrl');

var showNews = false;
ConnectivityMonitor.startWatching().then(function(result) {
// promise
console.log('ConnectivityMonitor result: ', result);
showNews = result;
$scope.showNews = showNews;

console.log('showNews: ', showNews);
if(showNews) {
displayNews();
}
}, function(error) {
console.error(error);
});

function displayNews() {
// do some stuff
}
};
newsCtrl.$inject = ['$scope', '$http', '$ionicLoading', 'PostService', 'BookMarkService', 'ConnectivityMonitor'];


My factory:

// ### ConnectivityMonitor ###
var ConnectivityMonitor = function ($rootScope, $cordovaNetwork, $q) {
console.log('ConnectivityMonitor');

var monitorNow = {
isOnline: isOnline,
isOffline: isOffline,
startWatching: startWatching
};
var deferred = $q.defer();

function isOnline() {
if(ionic.Platform.isWebView()) {
deferred.resolve($cordovaNetwork.isOnline());
} else {
deferred.resolve(navigator.onLine);
}
return deferred.promise;
};

function isOffline() {
if(ionic.Platform.isWebView()) {
deferred.resolve(!$cordovaNetwork.isOnline());
} else {
deferred.resolve(!navigator.onLine);
}
return deferred.promise;
};

function startWatching() {
if(ionic.Platform.isWebView()){
$rootScope.$on('$cordovaNetwork:online', function(event, networkState) {
console.log("went online");
console.log("event: ", event);
console.log("networkState: ", networkState);
deferred.resolve($cordovaNetwork.isOnline());
});
$rootScope.$on('$cordovaNetwork:offline', function(event, networkState) {
console.log("went offline");
console.log("event: ", event);
console.log("networkState: ", networkState);
deferred.resolve(!$cordovaNetwork.isOnline());
});
}
else {
window.addEventListener("online", function(e) {
console.log("went online");
console.log("event: ", e);
deferred.resolve(navigator.onLine);
}, false);
window.addEventListener("offline", function(e) {
console.log("went offline");
console.log("event: ", e);
deferred.resolve(!navigator.onLine);
}, false);
}
return deferred.promise;
};

console.log('isOnline: ', monitorNow.isOnline());
console.log('isOffline: ', monitorNow.isOffline());
console.log('startWatching: ', monitorNow.startWatching());

return monitorNow;
};
ConnectivityMonitor.$inject = ['$rootScope', '$cordovaNetwork', '$q'];

Answer

Your code looks quite complicated to me, maybe you want to take a look at a demo app of mine, which does pretty much the same. It's not an Ionic app, but Angular and TypeScript...

First of all I built a service to get the online state and store it in the variable deviceIsOnline.

class NetworkStatusService implements INetworkStatusService {
    deviceIsOnline: boolean;

    constructor() {
        document.addEventListener("deviceready", () => {
            if (navigator.connection.type === Connection.NONE) {
                this.deviceIsOnline = false;
            } else {
                this.deviceIsOnline = true;
            }
        });

        document.addEventListener("offline", () => {
            this.deviceIsOnline = false;
        });
        document.addEventListener("online", () => {
            this.deviceIsOnline = true;
        });
    }
}

I'm injecting this service into my controller and make use of the deviceIsOnline variable.

class IndexController {
    static $inject = ["cordovaStarter.NetworkStatusService"];
    constructor(private networkStatusService: INetworkStatusService) {
    }

    showNetworkStatus(): void {
        if (this.networkStatusService.deviceIsOnline) {
            alert("Online");
        } else {
            alert("Offline");
        }
    }
}

In your case you might want to watch the deviceIsOnline variable, so you can execute code everytime the variable changes, instead of reacting on a button click... This might help to understand the watch-pattern, if you don't already know it ;)


For the sake of completness, note that I'm hiding my implementation behind following interface:

interface INetworkStatusService {
    deviceIsOnline: boolean;
}