8

I am new to Angular/Ionic. Before using Angular/Ionic, at the launch of my app, I was checking if we were under Phonegap or a browser using and storing this information in a global boolean variable and then checking if the app was online or offline and storing it to a global variable too, like this :

var isPhoneGap;
var connectionStatus;
isPhoneGap = checkIfPhoneGap();

//later in the code :

connectionStatus = checkIfOnline();

function checkIfPhoneGap() {
    var app = document.URL.indexOf( 'http://' ) === -1 && document.URL.indexOf( 'https://' ) === -1; // && document.URL.indexOf( 'file://' );
    if ( app ) {
        return true;
    } else {
        return false;
    }
}
function checkIfOnline() {  
    if ( isPhoneGap ) {
        if (checkConnection() == "none" ) {
            connectionStatus = 'offline'; 
        } else {
            connectionStatus = 'online';
        }
        function checkConnection() {
            var networkState = navigator.network.connection.type;
            var states = {};
            states[Connection.UNKNOWN]  = 'Unknown connection';
            states[Connection.ETHERNET] = 'Ethernet connection';
            states[Connection.WIFI]     = 'WiFi connection';
            states[Connection.CELL_2G]  = 'Cell 2G connection';
            states[Connection.CELL_3G]  = 'Cell 3G connection';
            states[Connection.CELL_4G]  = 'Cell 4G connection';
            states[Connection.NONE]     = 'No network connection';
            //console.log('Connection : ' + Connection);
            //console.log('Connection type: ' + states[networkState]);
            return networkState;
        }
    } else {
        connectionStatus = navigator.onLine ? 'online' : 'offline';
    }
    return connectionStatus;
}

Now I would like to do the same with Angular/Ionic, I understand that I have to use a "Service". But is it the best way to make this information available through all the code ?

I am doing the following, but is it the "best practice" ?

in index.html :

<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
<script src="js/services.js"></script>

in services.js :

angular.module('SnowBoard.services', [])

.factory('isPhoneGap', function() {

    var appp = document.URL.indexOf( 'http://' ) === -1 && document.URL.indexOf( 'https://' ) === -1; // && document.URL.indexOf( 'file://' );
    if ( appp ) {
        return true;
    } else {
        return false;
    }

})

;

in app.js :

angular.module('SnowBoard', ['ionic', 'SnowBoard.controllers', 'SnowBoard.services'])

.run(["isPhoneGap","$ionicPlatform", function(isPhoneGap, $ionicPlatform) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if(window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if(window.StatusBar) {
      // org.apache.cordova.statusbar required
      StatusBar.styleDefault();
    }
  });

  //CHECK IF ONLINE
  connectionStatus = checkIfOnline(isPhoneGap);

  //DEBUG
  //var debugOptionUseLocalDB=0;
  //updateProDB(connectionStatus, debugOptionUseLocalDB);
}])
.config(function($stateProvider, $urlRouterProvider) {
//...all state configurations
})
.config(function($stateProvider, $urlRouterProvider) {
//...
});

This works for now, but I need the boolean isPhoneGap to be available everywhere I need it (almost everywhere in my app).

Can you converge to the best practice to do this ?

Thanks

3 Answers 3

10

You should not set variables using $rootScope, and try to refrain from using $scope as much as possible. Using LocalStorage is okay, but this data will persist. I would recommend setting up a factory to store and retrieve variables using SessionStorage. SessionStorage is tied to the tab you have open, so the data is gone when it is closed.

This is one of my session storage services. I throw $cookieStorage in case local storage isn't available. Also, localStorage can only store strings. This is why you will see me converting objects and arrays to and from JSON as needed. After injecting sessionService, I need only call sessionService.store(name, data) to store a session variable or sessionService.persist(name, data) to store persistent data i.e. userName if "Remember Me" is checked. :

.service('sessionService', ['$cookieStore', function ($cookieStore) {
    var localStoreAvailable = typeof (Storage) !== "undefined";
    this.store = function (name, details) {
        if (localStoreAvailable) {
            if (angular.isUndefined(details)) {
                details = null;
            } else if (angular.isObject(details) || angular.isArray(details) || angular.isNumber(+details || details)) {
                details = angular.toJson(details);
            };
            sessionStorage.setItem(name, details);
        } else {
            $cookieStore.put(name, details);
        };
    };

    this.persist = function(name, details) {
        if (localStoreAvailable) {
            if (angular.isUndefined(details)) {
                details = null;
            } else if (angular.isObject(details) || angular.isArray(details) || angular.isNumber(+details || details)) {
                details = angular.toJson(details);
            };
            localStorage.setItem(name, details);
        } else {
            $cookieStore.put(name, details);
        }
    };

    this.get = function (name) {
        if (localStoreAvailable) {
            return getItem(name);
        } else {
            return $cookieStore.get(name);
        }
    };

    this.destroy = function (name) {
        if (localStoreAvailable) {
            localStorage.removeItem(name);
            sessionStorage.removeItem(name);
        } else {
            $cookieStore.remove(name);
        };
    };

    var getItem = function (name) {
        var data;
        var localData = localStorage.getItem(name);
        var sessionData = sessionStorage.getItem(name);

        if (sessionData) {
            data = sessionData;
        } else if (localData) {
            data = localData;
        } else {
            return null;
        }

        if (data === '[object Object]') { return null; };
        if (!data.length || data === 'null') { return null; };

        if (data.charAt(0) === "{" || data.charAt(0) === "[" || angular.isNumber(data)) {
            return angular.fromJson(data);
        };

        return data;
    };

    return this;
}])

$cookieStore is part of ngCookies. Make sure you have angular-cookies.js included and load ngCookies as you would any module. Angular ngCookies

Sign up to request clarification or add additional context in comments.

5 Comments

Hi, thanks for your answer. But isn't there a way to use some kind of "Global variable" with angular ? I mean these variables, I need them everywhere in the code (and in several tabs too).
Yes, there is. No, you shouldn't use it. Javascript does not lend well to globals. The best practice is to use a factory or service to share data between controllers. The hack is to use $rootScope.
I just updated your code, because there was an error in the if else. And now I have another error from angular : Uncaught Error: [$injector:unpr] Unknown provider: $cookieStoreProvider <- $cookieStore <- sessionService <- updateProDB can you help me fix it ?
Thanks for the edit. $cookieStore is part of ngCookies. Make sure you have angular-cookies.js included and load ngCookies as you would any module. code.angularjs.org/1.2.27/docs/api/ngCookies
indeed, I have included and loaded ngCookies. I get a new error from your code. When I try to .store, I get the error : TypeError: Converting circular structure to JSON at Object.stringify (native) at Object.toJson (http://localhost:8100/lib/ionic/js/ionic.bundle.js:8746:15) at store (http://localhost:8100/js/services.js:229:35) from the line : details = angular.toJson(details);...it seems this is because in the object I am trying to store there is an angular thing : weightunit: select#weightunit.ng-pristine.ng-valid ... can you help please ?
3

First off, I'm pretty new to both Ionic and Angular, however I had the same problem with my web app Angular and I have done following to get it working

  1. assign variables to $rootScope, that way it's visible to all the controllers

  2. assign variables to $scope , which is visible by current context. Ex: controller and the html pages uses that controller

  3. localStorageService, because this will hold the values even after user refreshes the page.

Again please note, this is what I did in my Angular web app and might not be the best practices, but I hope you get the idea.

2 Comments

$rootScope is working fine with me (storing the service URI address) . But what is the difference between $rootScope and window.localStorage.setItem ??
The difference is that, localStorage data will persist even when the app is closed util explicitly cleared. But, the rootScope value is lost as soon as the page is refreshed/closed.
0

There are methods available in ionic.Platform that assist in getting back the data you need in regards to the device type.

http://ionicframework.com/docs/api/utility/ionic.Platform/

You could alternatively look at adding ngCordova, which has a bunch of useful wrappers around cordova plugins, including the device plugin.

http://ngcordova.com/docs/#Device

1 Comment

Hi, thanks for answering, my question was not really on how to detect the device, because I am pretty happy with my function. But it was more on how to make the boolean variable available everywhere to the code, a bit like a global variable. I've edited my question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.