I'm using angularJS
to build a simple single page application using AJAX, but I'm running into a problem when users use the native back button.
angular.module('myApp', ['ionic', 'myApp.controllers', myApp.services])
.config(function ($routeProvider, $locationProvider) {
$routeProvider.when('/home', {
templateUrl: 'templates/feed.html',
controller: 'MenuCtrl',
reloadOnSearch: false
});
$routeProvider.when('/checkin/view/:id', {
templateUrl: 'templates/checkin.html',
controller: 'MenuCtrl'
});
$routeProvider.otherwise({
redirectTo: '/home'
});
$locationProvider.html5Mode(true)
})
UPDATE: moved $http out of controls per feedback, and suggestions:
And my services.js
file:
angular.module('myApp.services', [])
.factory('FeedService', ['$http', function($http){
var state = {};
var loadFeed = function(){
$http({
method: 'GET',
url: 'http://api.example',
}).success(function(data){
// With the data succesfully returned, call our callback
state = data.response;
console.log(data);
}).error(function(){
alert("error");
});
};
loadFeed();
return {
getState: function(scope){
return state;
}
};
}])
And my controller.js
file:
angular.module('myApp.controllers', [])
.controller('MenuCtrl', function($scope, $http, $location, FeedService) {
// feedback per second answer
$scope.items = FeedService.getState();
})
.controller('CheckinCtrl', function($scope, $routeParams) {
$scope.checkin_id = $routeParams.id;
console.log($routeParams.id);
});
My main index.html
is setup like this:
<body ng-app="untappd">
<div ng-view></div>
</body>
This works great from navigation from a feed (/home)
, to a check-in page (/checkin/view/:id)
but, once the user hits the native back button on the browser or using window.history.back()
, code in the controller
is called again, which makes the AJAX call to pull down the user's friend feed. Should I be using ng-show
instead of using ng-view
for this use case, and create individual "pages" for each content I want to show? I was concerned with the performance, but it appears that I can't get data to persist in each ng-view
without it having to re-call the templates. Any guidance here?
UPDATE: I have changed this to incorporate the Best Practices, by adding the $http
request at the services
level, instead of the controller
level. I still run in to the issue of the getState request being fired, before the the AJAX of the $http
is complete, thus having an empty state, and nothing to render the $scope
.
Yep, the Back button and the the Refresh button are a real pain. You have two choices:
You keep things simple and just allow your state to be fetched for each location change. This treats a user triggered back button click or a refresh as any normal location change. Data re-fetching can be mitigated by http caching.
You maintain your own state on the client and restore it when required, possibly using SessionStorage
to keep things clean.
I chose the latter option and it all works just fine for me. See these self answered questions for detailed code examples.
Use a service to keep a singleton state, which exposes functions to get/reload/etc. Here is a very simple example, just to get you started:
.factory('FeedService', ['$http', function($http){
var state = {};
var loadFeed = function(){
$http.get('http://api.example.com').then(function(result){
state.feed = result.items;
});
};
// load the feed on initialisation
loadFeed();
return {
getState: function(){
return state;
}
};
}])
.controller('MenuCtrl', ['$scope', 'FeedService', function($scope, FeedService) {
// assign the feed container to any scope that you want to use for view
$scope.cont = FeedService.getState();
})
Again, this is very basic, and is simply showing you how you can use a service to store a persistent state between routes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With