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.
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)
Si vous utilisez un médiateur, vous diminuerez votre out-degré (fan-out) d'un facteur 2.
Avantages:
Inconvénient(?):
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);
};