White Screen, but everything still works

My app works fine in the browser. It also opens up to the login screen on my phone like it’s supposed to, but after logging in, on the phone, the screen is blank. I can watch the requests on the server as I press where the buttons are supposed to be, but the screen stays blank.

Can someone tell me what i’m doing wrong?

###Controller:

angular.module('finance')
.controller('addExpenseCtrl', function($scope, Expense, ionicToast, $state) {
  $scope.expenseData = {};
  $scope.newExpense = function () {
    var expense = new Expense($scope.expenseData);
    expense.$save()
    .then(function(expense) {
      $state.go("private.home");
      ionicToast.show('Expense Added.', 'bottom', false, 1500);
    })
    .catch(function(errors) {
      var errorMessage = [];
      angular.forEach(errors.data, function(key, value) {
        errorMessage.push(value + " " + key);
      });
      ionicToast.show(errorMessage, 'bottom', false, 2500);
    });
  };
})

.controller('loginCtrl', function($scope, $auth, ionicToast, $state) {
	$scope.loginData = {};
	$scope.submitLogin = function() {
		$auth.submitLogin($scope.loginData)
		.then(function(resp) {
			$state.go("private.home");
      ionicToast.show('Login Successful.', 'bottom', false, 1500);
		})
		.catch(function(resp) {
			var errorMessage = [];
      angular.forEach(resp.errors, function(value) {
        errorMessage.push(value);
      });
      ionicToast.show(errorMessage, 'bottom', false, 2500);
		});
	};
})

.controller('addIncomeCtrl', function($scope, Income, ionicToast, $state) {
  $scope.incomeData = {};
  $scope.newIncome = function () {
    var income = new Income($scope.incomeData);
    income.$save()
    .then(function(expense) {
      $state.go("private.home");
      ionicToast.show('Income Added.', 'bottom', false, 1500);
    })
    .catch(function(errors) {
      var errorMessage = [];
      angular.forEach(errors.data, function(key, value) {
        errorMessage.push(value + " " + key);
      });
      ionicToast.show(errorMessage, 'bottom', false, 2500);
    });
  };
})

.controller('viewCtrl', function($scope, Income, Expense, $ionicLoading) {	
  $scope.finances = [];
  Expense.get()
  .$promise.then(function (response) {
    angular.forEach(response.expenses, function(expense) {
      expense.type = "expense";
      $scope.finances.push(expense);
    });
  });
  Income.get()
  .$promise.then(function (response) {
    angular.forEach(response.incomes, function(income) {
      income.type = "income";
      $scope.finances.push(income);
      $scope.hide = function(){
		    $ionicLoading.hide();
		  };
    });
  });
})

.controller('editIncomeCtrl', function($scope, Income, ionicToast, $stateParams, $state) {
	
	$scope.incomeData = {};

	var income = Income.get({id:$stateParams.id})
	.$promise.then(function (response) {
		$scope.incomeData = response.income;
	});

	$scope.updateIncome = function () {
		Income.update({id:$stateParams.id}, $scope.incomeData)
    .$promise.then(function(response) {
      $state.go("private.viewFinances", {}, {location: 'replace'});
      ionicToast.show('Updated Successfully.', 'bottom', false, 1500);
    })
    .catch(function(errors) {
      var errorMessage = [];
      angular.forEach(errors.data, function(key, value) {
        errorMessage.push(value + " " + key);
      });
      ionicToast.show(errorMessage, 'bottom', false, 2500);
    });
	};

	$scope.deleteIncome = function () {
		Income.delete({id:$stateParams.id})
		.$promise.then(function(response) {
			$state.go("private.viewFinances");
			ionicToast.show("Successfully deleted.", 'bottom', false, 2500);
		})
		.catch(function(response) {
			ionicToast.show(response.status, 'bottom', false, 2500);
		});
	};
})

.controller('editExpenseCtrl', function($scope, Expense, ionicToast, $state, $stateParams) {
	
	$scope.expenseData = {};

	var expense = Expense.get({id:$stateParams.id})
	.$promise.then(function (response) {
		$scope.expenseData = response.expense;
	});

	$scope.updateExpense = function () {
		Expense.update({id:$stateParams.id}, $scope.expenseData)
    .$promise.then(function(response) {
      $state.go("private.viewFinances", {}, {location: 'replace'});      
      ionicToast.show('Updated Successfully.', 'bottom', false, 1500);
    })
    .catch(function(errors) {
      var errorMessage = [];
      angular.forEach(errors.data, function(key, value) {
        errorMessage.push(value + " " + key);
      });
      ionicToast.show(errorMessage, 'bottom', false, 2500);
    });
	};

	$scope.deleteExpense = function () {
		Expense.delete({id:$stateParams.id})
		.$promise.then(function(response) {
			$state.go("private.viewFinances");
			ionicToast.show("Successfully deleted.", 'bottom', false, 2500);
		})
		.catch(function(response) {
			ionicToast.show(response.status, 'bottom', false, 2500);
		});
	};
})

.controller('homeCtrl', function($scope, $auth, $state) {
  $scope.reload = function() {
    $state.reload();
  };
	$scope.logout = function() {
		$auth.signOut()
    .then(function(resp) {
    	$state.go('login')
    });
	}
});

###app.js:

"use strict";
 angular.module('finance', ['ionic', 'ngResource', 'ionic-toast', 'angularMoment', 'ng-token-auth'])

.config(function($authProvider) {
  $authProvider.configure({
    apiUrl: 'http://development.strawzberry.com:3000/v0',
    storage: 'localStorage',
  });
})

.config(function($stateProvider, $urlRouterProvider) {
  $stateProvider
  .state('login', {
    url: '/login',
    templateUrl: 'templates/login.html'
  })
  .state('private', {
    url: '/private',
    abstract: true,
    template: '<ui-view/>',
    resolve: {
      auth: function($auth) {
        console.log("Validate User called");
        return $auth.validateUser();
      }
    }
  })
  .state('private.home', {
    url: '/home',
    templateUrl: 'templates/home.html'
  })
  .state('private.addExpense', {
    url: '/addExpense',
    templateUrl: 'templates/addExpense.html'
  })
  .state('private.addIncome', {
    url: '/addIncome',
    templateUrl: 'templates/addIncome.html'
  })
  .state('private.viewFinances', {
    cache: false,
    url: '/view',
    templateUrl: 'templates/view.html'
  })
  .state('private.editIncome', {
    url: '/editIncome/:id',
    templateUrl: 'templates/editIncome.html'
  })
  .state('private.editExpense', {
    url: '/editExpense/:id',
    templateUrl: 'templates/editExpense.html'
  });

  $urlRouterProvider.otherwise('/login');
})

.run(function($ionicPlatform, $rootScope, $state) {
  $rootScope.$on("$stateChangeError", console.log.bind(console));
  $rootScope.$on("$stateChangeError", function(err) {
    $state.go('login');
  });

  $rootScope.$on('auth:validation-error', function(error) {
    console.log("Validatition Error")
  });
  $rootScope.$on('auth:invalid', function(error) {
    console.log("Invalid Token")
  });
  $rootScope.$on('auth:validation-success', function(resp) {
    console.log("Validation Success")
  });
  $rootScope.$on('auth:logout-success', function(ev) {
    console.log("Logged Out");
  });
  $rootScope.$on('auth:login-success', function(ev, user) {
    console.log("Logged in as " + user.email);
  });
  $rootScope.$on('auth:login-error', function(ev, user) {
    console.log("There was an error logging in");
  });
  $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) {
      StatusBar.styleDefault();
    }
  });
});
1 Like

Ok, after days of troubleshooting I finally found the problem.

This

.state('private', {
  url: '/private',
  abstract: true,
  template: '<ui-view/>',
  resolve: {
    auth: function($auth) {
      console.log("Validate User called");
      return $auth.validateUser();
    }
  }
})

needs to be this

.state('private', {
  url: '/private',
  abstract: true,
  template: '<ion-nav-view></ion-nav-view>',
  resolve: {
    auth: function($auth) {
      console.log("Validate User called");
      return $auth.validateUser();
    }
  }
})

The template needs to be the ion-nav-view rather then ui-view.

For me, the completely functional white screen happened after logging out and logging back in. Copied and pasted from this link: javascript - Is it possible to clear the view cache in Ionic? - Stack Overflow

logging in with another user was showing me stale/cached view. You can do cache: false at the state definition level but that entirely disables cache for that state in your app.

What you can rather do is clear all the cached view and history when user is on signin/login state of your application (as you said). Seems ideal.

// code inside your signin controller
$scope.$on("$ionicView.enter", function () {
   $ionicHistory.clearCache();
   $ionicHistory.clearHistory();
});