5 min read

Users expect certain things to simply work in every mobile app. And if they don’t work as expected, users delete your app and even worse they will probably give it a bad rating. Settings are one of those things users expect to simply work. Whenever a user makes a change to your app’s setting page, they expect that the rest of the app will pick up that change and that those changes will be correctly persisted so that whenever they use the app again, the changes they made will be remembered.

There is nothing too difficult about getting persistence to work correctly in an Ionic app, but there are a few road bumps that this post can help you to avoid. For an example, we will use the Ionic side menu starter template and add a settings page to it (beta 14 of Ionic was used for this post). There is nothing special about the settings page, in fact, settings can be persisted from anywhere in the application. The settings page just gives a nice place to play with things. And we can see how to persist values as they are changed by the user.

The first part of our settings strategy is that we will keep all of our individual settings in the Settings object. This is a personal preference of mine. My app always serializes and deserializes all of the individual properties of the Settings object. Anytime I want something persisted, I add it to the Settings object and the system takes care of the rest.

Next, we use an Angular Value object to hold the settings. A value is one of Angular’s providers, like factories, services, providers, and constants. And unlike its cousin, the constant, values can be changed. So a value gives us a nice place to store our settings object and the values we put in it serve as the default values.

angular.module('starter')
   .value("Settings", {
       searchRadius: {value: "5"},
       acceptsPushNotification: true,
       hasUserSeenMessage: false,
       pagesPerLoad: 20
   });

At the base of settings strategy is the HTML5 local storage. Local storage gives web apps a nice place to store information in string based key value pairs. If you’re wondering how we get types besides strings into storage, wonder no more. Part of the magic and the reason why it is nice to keep everything in a single object is that we are going to convert that single object to and from a string using JSON.

Inside of the file, “localstorage-service.js” there are only two methods in the services API. The first is serializeSettings and the second is deserializeSettings. Both do exactly what their names imply. There is also an internal only method in Local Storage, checkLocalStorage. It is only used for diagnostic purposes, since it is only used to write where or not the device has local storage to the console log.

The final thing that Local Storage does is call deserializeSettings once during its startup. This gives the settings object the last values stored. If there are no saved values, it uses the Settings object stored in values. One other bit of weirdness which should be explained is why we copy properties using angular extend instead of simply copying the whole object. If we ever modify the entire angular value object, it returns to the default values and our changes are lost. We could write our function to copy the properties, but angular includes extend which copies the properties exactly the way we need them.

function deserializeSettings() {
   var newSettings, rawSettings = localStorage[settings];
   if(rawSettings) {
        newSettings = JSON.parse(rawSettings);
       if (newSettings) {
           // use extend since it copies one property at a time
           angular.extend(Settings, newSettings);
           console.log("Settings restore");
       }
   }
}

In the Settings controller we bind the values from our Settings object to widgets on the page. It is not an accident that we name the property the same thing on the $scope object as on the Settings object. This makes updating the property easier, if we access the object using JavaScript bracket notation, we can access both the $scope and Settings object at the same time. We use this in the onChange method which is called anytime the value of a widget is changed. All of the widgets call this onChange method.

if (!Settings.hasUserSeenMessage) {
   Settings.hasUserSeenMessage = true;
   LocalStorageService.serializeSettings();
   $ionicPopup.alert({
       title: 'Hi There',
       template: '<div class="text-center">You are a first time user.</div>'
   });
}

// set the initial values for the widgets
$scope.searchRadius = Settings.searchRadius;
$scope.acceptPush = Settings.acceptPush;

// when a widget is changed, come here and update the setting object too
$scope.onChange = function (type, value) {
   $scope[type] = value;
   Settings[type] = value;
   LocalStorageService.serializeSettings();
};

We also demonstrate how to persist values programmatically. The hasUserSeenMessage property is checked in the code. If the user hasn’t seen our one time message, we set the value to true, persist the value to local storage, then display the message. Anytime you want to persist Settings, simply call LocalStorageService.serializeSettings.

About the author

Troy Miles, aka the Rockncoder, began writing games in assembly language for early computers like the Apple II, Vic20, C64, and the IBM PC over 35 years ago. Currently he fills his days writing web apps for a Southern California based automotive valuation and information company. Nights and weekends he can usually be found writing cool apps for mobile and web or teaching other developers how to do so. He likes to post interesting code nuggets on his blog: http://therockncoder.com and videos on his YouTube channel: https://www.youtube.com/user/rockncoder. He can be reached at [email protected]

The complete code of this tutorial is in my GitHub repo at https://github.com/Rockncoder/settings. Now that you know one way to persist settings, there is no excuse for not giving users a settings page which persist data properly to the device.

LEAVE A REPLY

Please enter your comment!
Please enter your name here