Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I need to track when a user changes the state of a checkbox in Ionic, save it to localStorage, and then use it to load again later - so it remembers their settings.

My toggle code looks like this:

<li class="item item-toggle">
     National Insurance {{ni_toggle}}
     <label class="toggle toggle-positive">
       <input type="checkbox" ng-model="ni_toggle" ng-click="updateLocalStorage()" id="has_national_insurance" name="has_national_insurance">
       <div class="track">
         <div class="handle"></div>
       </div>
     </label>
  </li>

And in my controller I have:

angular.module('starter.controllers', [])

.controller('SettingsCtrl', function($scope, $ionicPlatform) {
    $ionicPlatform.ready(function() {
    // Ready functions

    });

 $scope.updateLocalStorage = function() {

    window.localStorage.setItem( 'has_national_insurance', $scope.ni_toggle );
    console.log( $scope.ni_toggle );

}

})

However, it logs out to the console as undefined. If I explicitly set $scope.ni_toggle = false; it will log false and won't update to true when I toggle the checkbox to on.

EDIT:

app.js:

// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
// 'starter.services' is found in services.js
// 'starter.controllers' is found in controllers.js
angular.module('starter', ['ionic', 'starter.controllers', 'starter.services'])

  .run(function($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();
      }

    });
  })



.config(function($stateProvider, $urlRouterProvider) {

  // Ionic uses AngularUI Router which uses the concept of states
  // Learn more here: https://github.com/angular-ui/ui-router
  // Set up the various states which the app can be in.
  // Each state's controller can be found in controllers.js
  $stateProvider

    // setup an abstract state for the tabs directive
    .state('tab', {
      url: "/tab",
      abstract: true,
      templateUrl: "templates/tabs.html"
    })

    // Each tab has its own nav history stack:

    .state('tab.dash', {
      url: '/dash',
      views: {
        'tab-dash': {
          templateUrl: 'templates/tab-dash.html',
          controller: 'DashCtrl'
        }
      }
    })

    .state('tab.settings', {
      url: '/settings',
      views: {
        'tab-settings': {
          templateUrl: 'templates/tab-settings.html',
          controller: 'SettingsCtrl'
        }
      }
    })

    .state('tab.info', {
      url: '/info',
      views: {
        'tab-info': {
          templateUrl: 'templates/tab-info.html',
          controller: 'InfoCtrl'
        }
      }
    })

        .state('tab.about', {
      url: '/about',
      views: {
        'tab-about': {
          templateUrl: 'templates/tab-about.html',
          controller: 'AboutCtrl'
        }
      }
    })

  // if none of the above states are matched, use this as the fallback
  $urlRouterProvider.otherwise('/tab/dash');

});

controllers.js:

angular.module('starter.controllers', [])

.controller('DashCtrl', function($scope) {
})

.controller('SettingsCtrl', function($scope, $window, $ionicPlatform) {
    $ionicPlatform.ready(function() {

    });

    $scope.ni_toggle = $window.localStorage.getItem('has_national_insurance') === "true";

    $scope.updateLocalStorage = function() {
            $window.localStorage.setItem( 'has_national_insurance', $scope.ni_toggle );
            console.log( $scope.ni_toggle );
        }   


})

.controller('InfoCtrl', function($scope) {
})

.controller('AboutCtrl', function($scope) {
});

templates/tab-settings.html:

<li class="item item-toggle">
     National Insurance {{ni_toggle}}
     <label class="toggle toggle-positive">
       <input type="checkbox" ng-model="ni_toggle" ng-change="updateLocalStorage()" id="has_national_insurance" name="has_national_insurance">
       <div class="track">
         <div class="handle"></div>
       </div>
     </label>
  </li>

Working example of the problem

share|improve this question
    
Can i see the entire controller? I need more context. –  pattmorter Aug 1 '14 at 12:30
    
That's all I have in the SettingsCtrl right now. Updated above ^ –  ian Aug 1 '14 at 12:54
    
You're problem is that $scope.ni_toggle isn't defined. Might seem "well duh" but if you look in your controller you have nothing that says $scope.ni_toggle = blah blah blah which is a dead giveaway for me. –  pattmorter Aug 1 '14 at 12:59

2 Answers 2

up vote 3 down vote accepted

I am not familiar with Ionic's oddities (if there are any), but from a general JS perspective there seem to be a few issues with your code.

  1. You are not initializing ni_toggle.

  2. You are using ngClick which will get fired before the model has been updated by the ngModel directive.
    You should use ngChange instead.

  3. In Angular, you should use $window instead of window (it doesn't hurt and it can prove useful in many cases (e.g. testing)).

  4. Note that localStorage can only store strings (not booleans). So, even if you pass false, it will be stored as 'false', which is equivalent to true when cast to boolean.


Taking the above into account, your code should look like this:

<input type="checkbox" ng-model="ni_toggle" ng-change="updateLocalStorage()" ... />

.controller('SettingsCtrl', function($scope, $window, $ionicPlatform) {
    $ionicPlatform.ready(function() {
        // Ready functions
    });

    $scope.ni_toggle = $window.localStorage.getItem('has_national_insurance') === 'true';
    $scope.updateLocalStorage = function () {
        $window.localStorage.setItem('has_national_insurance', $scope.ni_toggle);
        console.log($scope.ni_toggle);
    };
});

See, also, this short demo.

share|improve this answer
    
I tried using your demo code as-is and it persists to "true" no matter the state. Could it be to do with my UIRouter set up? I've updated the original question with the full code for app.js, controllers.js and templates/tab-settings.html. Thanks for your help so far :) –  ian Aug 1 '14 at 14:03
    
@ian: It seems like you haven't succeeded in using my code as-is. See note nr.4 and see my implementation (especially the === "true") part. –  ExpertSystem Aug 1 '14 at 15:02
    
Ah, that was me testing and forgetting to undo the changes. I've updated the code, but even with the === "true" it still only logs "true" in the console. I'm thinking at this point I should probably not be using ionic/angular until I understand the concepts better. It shouldn't be this difficult to get the state of a checkbox. –  ian Aug 1 '14 at 15:16
    
@ian: Did you change ngClick to ngChange ? It is kind of frustratin trying to debug an issue when it might or might not be a copy/paste issue. It would be best if you could reproduce the problem in plunkr, so we have something to work on. Getting the value of a checkbox isn't difficult indeed (as my answer demonstrates :)). –  ExpertSystem Aug 1 '14 at 15:23
    
Here you go, a plnkr of my app structure using your code. {{ni_toggle}} in tab-settings.html shows the correct state, but it only ever logs "true" in the console: plnkr.co/edit/s88qJ7jnJe1rWFVxYjUp?p=preview –  ian Aug 1 '14 at 15:57

I ran into a similar situation for displaying user information a while ago with my ionic app. I don't have my original source code in front of me but I'm pretty sure this is how you need to do it.

angular.module('starter.controllers', [])

    .controller('SettingsCtrl', function($scope, $ionicPlatform) {

        this.toggle = true; // make sure its defined somewhere

        $scope.ni_toggle = function() {
            return this.toggle;
        }

        $scope.updateLocalStorage = function() {
            window.localStorage.setItem(
                'has_national_insureance',
                $scope.ni_toggle
            );
            console.log($scope.ni_toggle);
        }

    });

Hope this gets you going in the right direction.

EDIT See ExpertSystem's answer. He answered it way better than I could.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.