Сохранить состояние просмотров в 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);
};