Сохранить состояние просмотров в AngularJS
Я разрабатываю приложение HTML 5 и вижу, где загружаются комментарии пользователей. Он рекурсивный: любой комментарий может иметь интерактивные суб-комментарии, которые загружаются в одном представлении и используют один и тот же контроллер.
Все в порядке. Но, когда я хочу вернуться, комментарии снова загружаются, и я теряю свою позицию и суб-комментарии, которые я загрузил.
Могу ли я сохранить состояние представления, когда вернусь? Я думал, что могу использовать какой-то трюк, например: добавить новое представление в любое время, когда я нажимаю на суб-комментарий и скрываю предыдущее представление. Но я не знаю, как это сделать.
Ответы
Ответ 1
Да, вместо того, чтобы загружать и сохранять состояние вашего интерфейса внутри своих контроллеров, вы должны сохранять состояние в службе. Это означает, что если вы это делаете:
app.config(function($routeProvider){
$routeProvider.when('/', {
controller: 'MainCtrl'
}).when('/another', {
controller: 'SideCtrl'
});
});
app.controller('MainCtrl', function($scope){
$scope.formData = {};
$scope./* other scope stuff that deal with with your current page*/
$http.get(/* init some data */);
});
вы должны изменить свой код инициализации на свою службу, а также состояние там, таким образом вы можете сохранить состояние между несколькими видами:
app.factory('State', function(){
$http.get(/* init once per app */);
return {
formData:{},
};
});
app.config(function($routeProvider){
$routeProvider.when('/', {
controller: 'MainCtrl'
}).when('/another', {
controller: 'SideCtrl'
});
});
app.controller('MainCtrl', function($scope, State){
$scope.formData = State.formData;
$scope./* other scope stuff that deal with with your current page*/
});
app.controller('SideCtrl', function($scope, State){
$scope.formData = State.formData; // same state from MainCtrl
});
app.directive('myDirective', function(State){
return {
controller: function(){
State.formData; // same state!
}
};
});
когда вы переходите назад и вперед по своим представлениям, их состояние будет сохранено, потому что ваша служба является одноэлементной, которая была инициализирована, когда вы впервые ввели ее в свой контроллер.
Также есть новый ui.router
, который имеет конечный автомат, это низкоуровневая версия $routeProvider
, и вы можете получить точное состояние сохранения зерна с помощью $stateProvider
, но в настоящее время оно экспериментально (и будет отправлено на angular 1.3)
Ответ 2
Использовать медиатор
Если вы используете посредник, вы уменьшаете свою степень (Fan-Out) в 2 раза.
Преимущества:
- Вы не связываете свой модуль напрямую с вашим сервером ($ http).
- Вы не связываете свой модуль с дополнительной службой (State).
- Все, что вам нужно для сохранения состояния, находится прямо на вашем контроллере ($ scope/$scope. $on, $emit, $broadcast).
- Ваш Медиатор знает больше и может направить приложение более эффективно.
Даунсайд (?):
- Ваши модули должны запускать интересные события ($ scope. $emit ('list://added/Item', $scope.list.id, item))
mediator.js
angular.module('lists.mediator', ['lists', 'list', 'item']).run(function mediate($rootScope){
var lists = [];
$rootScope.lists = lists;
$rootScope.$watch('lists', yourWatcher, true);
function itemModuleOrControllerStartedHandler(e, itemId, disclose){
if(!lists.length){
$http.get(...).success(function(data){
lists.push.apply(lists, data);
var item = getItem(lists, itemId);
disclose(item); // do not copy object otherwise you'll have to manage changes to stay synchronized
});
} else {
var item = getItem(lists, itemId);
disclose(item);
}
}
$rootScope.$on('item://started', itemModuleOrControllerStartedHandler);
});
// angular.bootstrap(el, ['lists.mediator'])
элемент-controller.js
var ItemController = function ItemController($scope, $routeParams){
var disclosure = $scope.$emit.bind($scope, 'item://received/data', (+new Date()));
$scope.itemId = $routeParams.id;
$scope.item = { id: -1, name: 'Nameless :(', quantity: 0 };
function itemDataHandler(e, timestamp, item){
$scope.item = item;
}
$scope.$on('item://received/data', itemDataHandler);
$scope.$emit('item://started', $scope.id, disclosure);
};