Ionic Build Dont Work (App works in Browser)

Hey there,
Im working on a To Do List app and finally added localStorage to it.
in the browser everything works fine, but if i install the apk on my Phone, the todolist is fully white and i cannot add tasks.
Its since i added localStorage. Maybe you can take a look at it.

index.html





    <link href="lib/ionic/css/ionic.css" rel="stylesheet">
    <link href="css/style.css" rel="stylesheet">

    <!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
    <link href="css/ionic.app.css" rel="stylesheet">
    -->

    <!-- ionic/angularjs js -->
    <script src="lib/ionic/js/ionic.bundle.js"></script>

    <!-- cordova script (this will be a 404 during development) -->
    <script src="cordova.js"></script>

    <!-- your app's js -->
    <script src="js/app.js"></script>
    <script src="lib/ngstorage/ngStorage.min.js"></script>
   
  </head>
  <body ng-app="starter" ng-controller="TodoCtrl">
    <ion-header-bar align-title="center" class="bar-balanced">
    <h1 class="title">Workaholic</h1>
    <a class="button button-icon icon ion-android-home" href="#/home"></a>
    <a class="button button-icon ion-compose icon" href="#/newtask"></a>
    </ion-header-bar>
    
      
      <ion-nav-view></ion-nav-view>
            
            
            
            <!-- todolist page -->
            <script id="templates/todo.html" type="text/ng-template">
                <ion-view view-title="todo">
                <ion-content>
                <ion-list>
                <ion-item ng-repeat="task in tasks" on-hold="edit(task)" on-double-tap="tasks.splice($index, 1)">
                 {{task.title}}
                </ion-item>
                </ion-list>
                </ion-content>
                </ion-view>
              </script>
              
              <!-- Page to add a Task in Todo -->
            <script id="templates/newtask.html" type="text/ng-template">
            <ion-view view-title="TaskAdd">
                <ion-content class="padding">
                    <div class="tasktitle">
                        <label class="item item-input">
                            <input type="text" placeholder="Add a Task Title" ng-model="todo.title">
                        </label>
                    </div>
                    <div class="taskdesc">
                        <label class="item item-input">
                            <input type="text" placeholder="Add a Description to the Task" ng-model="todo.desc">
                        </label>
                    </div>
                    <button ng-click="saveTask(todo)" class="button button-block button-positive"> Save </button>
                </ion-content>
            </ion-view>
            </script>

              <!-- countdown page -->
              <script id="templates/countdown.html" type="text/ng-template">
              <ion-view view-title="countdown">
              <ion-content ng-controller="CountCtrl">
              <div class="countdown" ng-show="countDown&gt;0"><span ng-if="minutes &lt; 10">0</span>{{minutes}}:<span ng-if="seconds &lt; 10">0</span>{{seconds}}</div>
              <div class="row">
                  <div class="spacer">
                      </div>
                  <div class="firstInp">
                    <label class="item item-input">
                      <input class="firstInp" id="input1" name="myform" ng-model="mininputVal" type="tel" placeholder="Min.">
                    </label>
                  </div>
                  <div class="secondInp">
                    <label class="item item-input">
                        <input class="secondInp" id="input2" name="myform" ng-model="secinputVal" type="tel" placeholder="Sec.">
                    </label>
                  </div>
                  </div>
                  <div class="countButton1">
                    <button id="countDownbutton" ng-disabled="countDown > 0 || !secinputVal" class="button button-balanced" ng-click="timerCountdown(mininputVal, secinputVal)">Start Countdown</button>
                    </div>
                  <div class="countButton2">
                    <button id="countDownbutton" ng-disabled="!countDown" class="button button-assertive" ng-click="stopCount()">Stop Countdown</button>
                  </div>
            </ion-content>
            </ion-view>
            </script>
            
            <!-- Home Site -->
            <script id="templates/home.html" type="text/ng-template">
            <ion-view view-title="home">
                <ion-content class="padding">
                    <h4>Hello User! Thank you for testing my App. <br />
                    Its not Finished at all, so if you have <br />
                    improvements or Ideas, just tell me them. <br />
                    <br />
                    </h4>
                    <h4>
                    Contact me: <br />
                    via Twitter - @JulianTheDev <br />
                    via Email - julianbe00@gmail.com <br />
                    </h4>
                    
                    <a class="button button-block icon-right ion-chevron-right button-assertive button-custom" ng-click="loadTask()">To Do's</a>
                    <a class="button button-block icon-right ion-chevron-right button-assertive button-custom" href="#/countdown">Countdown</a>
                    <a class="button button-block icon-right ion-chevron-right button-assertive button-custom" href="#/help">Help</a>
                </ion-content>
              </ion-view>
              </script>
              
            <!-- How It Works Site -->
            <script id="templates/help.html" type="text/ng-template">
            <ion-view view-title="help">
                <ion-content>
                    <div class="todohelp">
                    <h3>To Do</h3>
                    <h4>• Double Tap to delete a Task!</h4>
                    <h4>• Hold on the Task to edit it!</h4>
                    </div>
                </ion-content>
            </ion-view>
            </script>
  </body>
</html>

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'
var app = angular.module('starter', ['ionic', 'ngStorage'])

app.config(function($stateProvider, $urlRouterProvider) {
    
  $stateProvider
  .state('home', {
    url: '/home',
    templateUrl: 'templates/home.html'
  })
  .state('help', {
    url: '/help',
    templateUrl: 'templates/help.html'
  })
  .state('countdown', {
    url: '/countdown',
    templateUrl: 'templates/countdown.html'
  })
  .state('newtask', {
      url: '/newtask',
      templateUrl: 'templates/newtask.html'
  })
  .state('todo', {
    url: '/todo',
    templateUrl: 'templates/todo.html'
  });
  
  $urlRouterProvider.otherwise("home");
  
});

app.controller('TodoCtrl', function($scope, $ionicPopup, $ionicListDelegate, $state, $localStorage) {

    // Tasks are stored here
    $scope.tasks =
      [
        {title: "Double Tap To Delete a Task!"},
        {title: "Hold On The Task to Edit It!"},
      ];

      $scope.saveTask = function(todo){
          console.log(todo.title, todo.desc);
          $state.go('todo');
          $scope.tasks.push({title: todo.title});
          $localStorage.tasks = $scope.tasks;
      };
      
      $scope.loadTask = function(){
          $state.go('todo');
          $scope.tasks = $localStorage.tasks;
      }
      

// Edits a Task
    $scope.edit = function(task) {
      $scope.data = { response: task.title };
      $ionicPopup.prompt({
        title: "Edit Task",
        scope: $scope
      }).then(function(res) {    // promise 
        if (res !== undefined) task.title = $scope.data.response;
        $ionicListDelegate.closeOptionButtons();
      })
    };
})


// Countdown Controller
app.controller('CountCtrl', function countController($scope, $interval, $ionicPopup){
    $scope.countDown = 0; // number of seconds remaining
    var stop;
    $scope.mininputVal = "";
    $scope.secinputVal = "";
    $scope.minutes = $scope.mininputVal*60;
    $scope.seconds = $scope.secinputVal;

    // Countdown
    $scope.timerCountdown = function(minutes, seconds) {
        $scope.buttonclick = document.getElementById('countDownbutton')
        $scope.minutes = parseInt(minutes);
        $scope.seconds = parseInt(seconds);
    
        // Minutes/Seconds Flow + if above the limit
        if ($scope.mininputVal > 99){
            $scope.minutes = 99
        }
        if ($scope.secinputVal > 60){
            $scope.seconds = 60
        }
        if (!$scope.mininputVal){
        $scope.minutes = 0;
        }
        if (!$scope.secinputVal){
        $scope.seconds = 0;
        }
      // set number of seconds until the countdown is ready
      $scope.countDown =  parseInt($scope.mininputVal*60) + parseInt($scope.secinputVal);
      
      // start the countdown
      stop = $interval(function() {
          
        // decrement remaining seconds
        $scope.seconds--;
        $scope.countDown--;
        if ($scope.seconds === -1){
            $scope.seconds = 59;
            $scope.minutes--;
        }
        
        // Stop The Countdown
        $scope.stopCount = function () {
                //Set the Timer stop message.
                console.log("Timer Stopped.")
                //Cancel the Timer.
                if (angular.isDefined(stop)) {
                    $interval.cancel(stop);
                    $scope.countDown = 0;
                }
            };
            
        // if zero, stop $interval and show the popup
        if ($scope.countDown === 0){
          $interval.cancel(stop);
          $scope.running = false;
          console.log("Finished");
          var alertPopup = $ionicPopup.alert({
             title: 'The Countdown is Finished!',
             template: 'Youre Ready To Go!'});
        }
      },1000,0); // invoke every 1 second
    };
});

app.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    if(window.cordova && window.cordova.plugins.Keyboard) {
      // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
      // for form inputs)
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);

      // Don't remove this line unless you know what you are doing. It stops the viewport
      // from snapping when text inputs are focused. Ionic handles this internally for
      // a much nicer keyboard experience.
      cordova.plugins.Keyboard.disableScroll(true);
    }
    if(window.StatusBar) {
      StatusBar.styleDefault();
    }
  });
})

ngstorage. I’m guessing this would also require ngCordova. Download the ngCordova.js file and include it before the cordova.js in your index.html file. See if that works.

it dont works :frowning: maybe any other idea?

I actually don’t see why you need ngstorage if you just want to use localstorage. try removing ngcordova.js and ngstorage.min.js from your index.html file.

simply add something like this in your factory to make your code short and sweet.

.factory('$localstorage', ['$window', function($window) {
    return {
      set: function(key, value) {
        $window.localStorage[key] = value;
        console.log(key+' has been set with value: '+value);
     },
     get: function(key, defaultValue) {
        return $window.localStorage[key] || defaultValue;
     },
     setObject: function(key, value) {
        $window.localStorage[key] = JSON.stringify(value);
     },
     getObject: function(key) {
        return JSON.parse($window.localStorage[key] || '{}');
     },
     remove: function(key){
	$window.localStorage.removeItem(key);
     }
  }
}])

and then in your controller add $localstorage (not $localStorage) in your dependency, then you can use it like so:

$localstorage.get('tasks');
$localstorage.remove('tasks');
$localstorage.set('tasks', $scope.tasks);
etc etc...

Hope that helps.

do i have to get the tasks via ng-init? Sorry im very bad with localstorage xD

When i looked it up with console.log now it gives me this “tasks has been set with value: [object Object],[object Object],[object Object],[object Object]” but it dont really saves it to the tasks, so what can i do?

Sorry i forgot to say when saving $scope.tasks it needs to be saved in a string format. e.g.

$localstorage.set('tasks', JSON.stringify($scope.tasks));

When getting your info you need to parse it so that it can be used as an object like so:

$scope.tasks = JSON.parse($localstorage.get('tasks');

That should fix it.

First of all thank you, it works, but sometimes this error is thrown - "Error: [ngRepeat:dupes] Duplicates in a repeater are not allowed. Use ‘track by’ expression to specify unique keys. Repeater: task in tasks, Duplicate key: object:13, Duplicate value: {“title”:“TEAst”}"
So how can i disable to make same named Tasks?

forget it, it works xD Sorry for taking your time, but thank you very much!

Great. i’m glad it fixed your problem. :slight_smile: