web-dev-qa-db-fra.com

Enregistrer l'état des vues dans AngularJS

Je développe une application HTML 5 et ai une vue où les commentaires des utilisateurs sont chargés. Il est récursif: tout commentaire peut avoir des sous-commentaires cliquables qui se chargent dans la même vue et utilisent le même contrôleur.

Tout va bien. Mais, quand je veux revenir en arrière, les commentaires se chargent à nouveau et je perds ma position et les sous-commentaires que j'ai chargés.

Puis-je sauvegarder l'état de la vue lorsque je reviens? J'ai pensé que je pourrais peut-être utiliser une astuce, comme: ajouter une nouvelle vue à chaque fois que je clique sur un sous-commentaire et masque la vue précédente. Mais je ne sais pas comment le faire.

13
Alex

Oui, au lieu de charger et de conserver l'état de votre interface utilisateur dans vos contrôleurs, vous devriez conserver l'état dans un service. Cela signifie que si vous faites ceci:

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 */);
});

vous devriez changer votre code d'initialisation en votre service, et l'état là aussi, de cette façon vous pouvez garder l'état entre plusieurs vues:

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!
    }
  };
});

lorsque vous échangez vos points de vue, leur état est préservé, car votre service est un singleton, qui a été initialisé lors de sa première injection dans votre contrôleur.

Il y a aussi le nouveau ui.router, qui a une machine d'état, c'est une version de bas niveau de $routeProvider et vous pouvez affiner l'état de persistance du grain en utilisant $stateProvider, mais il est actuellement expérimental (et sera livré à la version angulaire 1.3)

23
pocesar

Utilisez un médiateur

Si vous utilisez un médiateur, vous diminuerez votre out-degré (fan-out) d'un facteur 2.

Avantages:

  • Vous ne couplez pas votre module directement à votre serveur ($ http).
  • Vous ne couplez pas votre module à un service supplémentaire (State).
  • Tout ce dont vous avez besoin pour la persistance des états se trouve dans votre contrôleur ($ scope/$ scope. $ Sur, $ emit, $ broadcast).
  • Votre médiateur en sait plus et peut diriger l'application plus efficacement.

Inconvénient(?):

  • Vos modules doivent déclencher des événements intéressant ($ 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'])

item-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);
};
1
Cody