Manter modelo de escopo ao alterar entre visões no AngularJS

Eu estou aprendendo AngularJS. Digamos que eu tenha / view1 usando My1Ctrl e / view2 usando My2Ctrl ; que pode ser navegado usando abas onde cada visão tem sua própria forma simples, mas diferente.

Como eu me certificaria de que os valores inseridos na forma de view1 não sejam redefinidos, quando um usuário sair e, em seguida, retornar à view1 ?

O que quero dizer é, como a segunda visita a ver1 pode manter exatamente o mesmo estado do modelo que eu deixei?

   

Eu levei um pouco de tempo para descobrir qual é a melhor maneira de fazer isso. Eu também queria manter o estado, quando o usuário sai da página e, em seguida, pressiona o botão Voltar, para voltar para a página antiga; e não basta colocar todos os meus dados no rootscope .

O resultado final é ter um serviço para cada controlador . No controlador, você só tem funções e variables ​​com as quais não se importa, se elas estiverem desmarcadas.

O serviço para o controlador é injetado por injeção de dependência. Como os serviços são singletons, seus dados não são destruídos como os dados no controlador.

No serviço, tenho um modelo. o modelo só tem dados – sem funções -. Dessa forma, ele pode ser convertido de JSON para persistir. Eu usei o localstorage html5 para persistência.

Por último eu usei window.onbeforeunload e $rootScope.$broadcast('saveState'); para permitir que todos os serviços saibam que devem salvar seu estado e $rootScope.$broadcast('restoreState') para que eles saibam restaurar seu estado (usado para quando o usuário sai da página e pressiona o botão Voltar para retornar ao página respectivamente).

Exemplo de serviço chamado userService para meu userController :

 app.factory('userService', ['$rootScope', function ($rootScope) { var service = { model: { name: '', email: '' }, SaveState: function () { sessionStorage.userService = angular.toJson(service.model); }, RestoreState: function () { service.model = angular.fromJson(sessionStorage.userService); } } $rootScope.$on("savestate", service.SaveState); $rootScope.$on("restorestate", service.RestoreState); return service; }]); 

exemplo userController

 function userCtrl($scope, userService) { $scope.user = userService; } 

A visão então usa binding como esta

 

{{user.model.name}}

E no módulo de aplicativo , dentro da function de execução eu manipulo a transmissão do saveState e restoreState

 $rootScope.$on("$routeChangeStart", function (event, next, current) { if (sessionStorage.restorestate == "true") { $rootScope.$broadcast('restorestate'); //let everything know we need to restore state sessionStorage.restorestate = false; } }); //let everthing know that we need to save state now. window.onbeforeunload = function (event) { $rootScope.$broadcast('savestate'); }; 

Como eu mencionei isso demorou um pouco para chegar a este ponto. É uma maneira muito limpa de fazê-lo, mas é uma boa parte da engenharia fazer algo que eu suspeitaria ser um problema muito comum no desenvolvimento em Angular.

Eu adoraria ver mais fácil, mas como maneiras limpas de lidar com a manutenção do estado entre os controladores, inclusive quando o usuário sai e retorna à página.

Um pouco atrasado para uma resposta, mas apenas atualizado violino com algumas das melhores práticas

jsfiddle

 var myApp = angular.module('myApp',[]); myApp.factory('UserService', function() { var userService = {}; userService.name = "HI Atul"; userService.ChangeName = function (value) { userService.name = value; }; return userService; }); function MyCtrl($scope, UserService) { $scope.name = UserService.name; $scope.updatedname=""; $scope.changeName=function(data){ $scope.updateServiceName(data); } $scope.updateServiceName = function(name){ UserService.ChangeName(name); $scope.name = UserService.name; } } 

$ rootScope é uma grande variável global, o que é bom para coisas únicas ou pequenos aplicativos. Use um serviço se você quiser encapsular seu modelo e / ou comportamento (e possivelmente reutilizá-lo em outro lugar). Além da postagem no grupo do Google, o OP mencionado, consulte também https://groups.google.com/d/topic/angular/eegk_lB6kVs/discussion .

Angular realmente não fornece o que você está procurando fora da checkbox. O que eu faria para conseguir o que você está depois é usar os seguintes add ons

Roteador de interface do usuário e extras de roteador de interface do usuário

Estes dois irão fornecer-lhe com estado de roteamento e estados fixos, você pode tab entre estados e todas as informações serão salvas como o escopo “permanece vivo” por assim dizer.

Verifique a documentação em ambos como é bastante simples, extras de roteador ui também tem uma boa demonstração de como funciona os estados pegajosos.

Eu tive o mesmo problema, isto é o que eu fiz: Eu tenho um SPA com múltiplas visões na mesma página (sem ajax), então este é o código do módulo:

 var app = angular.module('otisApp', ['chieffancypants.loadingBar', 'ngRoute']); app.config(['$routeProvider', function($routeProvider){ $routeProvider.when('/:page', { templateUrl: function(page){return page.page + '.html';}, controller:'otisCtrl' }) .otherwise({redirectTo:'/otis'}); }]); 

Eu tenho apenas um controlador para todas as visões, mas, o problema é o mesmo da pergunta, o controlador sempre atualiza os dados, para evitar esse comportamento eu fiz o que as pessoas sugerem acima e criei um serviço para esse fim, depois passe para o controlador da seguinte forma:

 app.factory('otisService', function($http){ var service = { answers:[], ... } return service; }); app.controller('otisCtrl', ['$scope', '$window', 'otisService', '$routeParams', function($scope, $window, otisService, $routeParams){ $scope.message = "Hello from page: " + $routeParams.page; $scope.update = function(answer){ otisService.answers.push(answers); }; ... }]); 

Agora eu posso chamar a function update de qualquer uma das minhas views, passar valores e atualizar meu model, não precisei usar html5 apis para persistência de dados (isso é no meu caso, talvez em outros casos seria necessário usar html5 apis como localstorage e outras coisas).

Uma alternativa aos serviços é usar o armazenamento de valor.

Na base do meu aplicativo eu adicionei este

 var agentApp = angular.module('rbAgent', ['ui.router', 'rbApp.tryGoal', 'rbApp.tryGoal.service', 'ui.bootstrap']); agentApp.value('agentMemory', { contextId: '', sessionId: '' } ); ... 

E, em seguida, no meu controlador, apenas faço referência ao armazenamento de valor. Eu não acho que vale a pena se o usuário fecha o navegador.

 angular.module('rbAgent') .controller('AgentGoalListController', ['agentMemory', '$scope', '$rootScope', 'config', '$state', function(agentMemory, $scope, $rootScope, config, $state){ $scope.config = config; $scope.contextId = agentMemory.contextId; ... 

Solução que funcionará para vários escopos e várias variables ​​dentro desses escopos

Esse serviço foi baseado na resposta de Anton, mas é mais extensível e funcionará em vários escopos e permite a seleção de várias variables ​​de escopo no mesmo escopo. Ele usa o caminho da rota para indexar cada escopo e, em seguida, os nomes da variável de escopo para indexar um nível mais profundo.

Crie serviço com este código:

 angular.module('restoreScope', []).factory('restoreScope', ['$rootScope', '$route', function ($rootScope, $route) { var getOrRegisterScopeVariable = function (scope, name, defaultValue, storedScope) { if (storedScope[name] == null) { storedScope[name] = defaultValue; } scope[name] = storedScope[name]; } var service = { GetOrRegisterScopeVariables: function (names, defaultValues) { var scope = $route.current.locals.$scope; var storedBaseScope = angular.fromJson(sessionStorage.restoreScope); if (storedBaseScope == null) { storedBaseScope = {}; } // stored scope is indexed by route name var storedScope = storedBaseScope[$route.current.$$route.originalPath]; if (storedScope == null) { storedScope = {}; } if (typeof names === "string") { getOrRegisterScopeVariable(scope, names, defaultValues, storedScope); } else if (Array.isArray(names)) { angular.forEach(names, function (name, i) { getOrRegisterScopeVariable(scope, name, defaultValues[i], storedScope); }); } else { console.error("First argument to GetOrRegisterScopeVariables is not a string or array"); } // save stored scope back off storedBaseScope[$route.current.$$route.originalPath] = storedScope; sessionStorage.restoreScope = angular.toJson(storedBaseScope); }, SaveState: function () { // get current scope var scope = $route.current.locals.$scope; var storedBaseScope = angular.fromJson(sessionStorage.restoreScope); // save off scope based on registered indexes angular.forEach(storedBaseScope[$route.current.$$route.originalPath], function (item, i) { storedBaseScope[$route.current.$$route.originalPath][i] = scope[i]; }); sessionStorage.restoreScope = angular.toJson(storedBaseScope); } } $rootScope.$on("savestate", service.SaveState); return service; }]); 

Adicione este código à sua function de execução no seu módulo de aplicativo:

 $rootScope.$on('$locationChangeStart', function (event, next, current) { $rootScope.$broadcast('savestate'); }); window.onbeforeunload = function (event) { $rootScope.$broadcast('savestate'); }; 

Injetar o serviço restoreScope em seu controlador (exemplo abaixo):

 function My1Ctrl($scope, restoreScope) { restoreScope.GetOrRegisterScopeVariables([ // scope variable name(s) 'user', 'anotherUser' ],[ // default value(s) { name: 'user name', email: 'user@website.com' }, { name: 'another user name', email: 'anotherUser@website.com' } ]); } 

O exemplo acima irá inicializar $ scope.user para o valor armazenado, caso contrário, será padronizado para o valor fornecido e salvará isso. Se a página for fechada, atualizada ou a rota for alterada, os valores atuais de todas as variables ​​de escopo registradas serão salvos e serão restaurados na próxima vez que a rota / página for visitada.

Você pode usar o evento $locationChangeStart para armazenar o valor anterior em $rootScope ou em um serviço. Quando você voltar, basta inicializar todos os valores armazenados anteriormente. Aqui está uma demonstração rápida usando $rootScope .

insira a descrição da imagem aqui

 var app = angular.module("myApp", ["ngRoute"]); app.controller("tab1Ctrl", function($scope, $rootScope) { if ($rootScope.savedScopes) { for (key in $rootScope.savedScopes) { $scope[key] = $rootScope.savedScopes[key]; } } $scope.$on('$locationChangeStart', function(event, next, current) { $rootScope.savedScopes = { name: $scope.name, age: $scope.age }; }); }); app.controller("tab2Ctrl", function($scope) { $scope.language = "English"; }); app.config(function($routeProvider) { $routeProvider .when("/", { template: "

Tab1 content

Name:

Age:

Fill the details and click on Tab2

", controller: "tab1Ctrl" }) .when("/tab2", { template: "

Tab2 content

My language: {{language}}

Now go back to Tab1

", controller: "tab2Ctrl" }); });
 < !DOCTYPE html>     Tab1 Tab2