在AngularJS的视图之间切换时维护范围的模型
我正在学习AngularJS。 比方说我有/ view1使用My1Ctrl和/ view2使用My2Ctrl ; 可以导航到使用选项卡,其中每个视图有自己的简单,但不同的forms。
如何确保以view1的formsinput的值不会重置,当用户离开,然后返回到view1 ?
我的意思是,第二次访问如何保持与我离开模型完全相同的状态?
我花了一些时间来研究这样做的最佳方式。 我也想保持状态,当用户离开页面,然后按下后退button,返回到旧页面; 而不仅仅是把我所有的数据都放到根目录 。
最终的结果是为每个控制器 提供服务 。 在控制器中,如果清除了函数和variables,则不需要关心它们。
控制器的服务是通过dependency injection来注入的。 由于服务是单例,它们的数据不会像控制器中的数据一样被销毁。
在服务中,我有一个模型。 该模型只有数据 – 没有function – 。 这样它可以从JSON来回转换来坚持下去。 我使用html5 localstorage进行持久化。
最后我用window.onbeforeunload
和$rootScope.$broadcast('saveState');
让所有的服务知道他们应该保存他们的状态,并且$rootScope.$broadcast('restoreState')
让他们知道恢复他们的状态(用于当用户离开页面并按回退键返回到页面)。
为我的userController调用userService的示例服务:
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; }]);
userController的例子
function userCtrl($scope, userService) { $scope.user = userService; }
该视图然后使用这样的绑定
<h1>{{user.model.name}}</h1>
在应用程序模块中 ,在运行函数中,我处理saveState和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'); };
正如我所提到的,这一段时间来到这一点。 这是一个非常干净的做法,但是在Angular开发时,做一些我认为是非常普遍的事情,这是相当不错的工程。
我希望看到更容易,但作为干净的方式来处理控制器之间的状态,包括当用户离开和返回到页面。
有点迟到的答案,但只是更新小提琴最佳做法
的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是一个很大的全局variables,对于一次性事物或者小应用程序来说是很好的select。 如果要封装模型和/或行为(可能在别处重复使用),请使用服务。 除了提到的OP之后的谷歌小组,另请参阅https://groups.google.com/d/topic/angular/eegk_lB6kVs/discussion 。
Angular并没有真正提供你正在寻找的开箱即用function。 我会做什么来完成你以后使用下面的附加
UI路由器和UI路由器附加function
这两个将为您提供基于状态的路由和粘滞状态,您可以在状态之间选项卡,所有信息将被保存为范围“保持活着”可以这么说。
检查这两个文件,因为它非常简单,UI路由器额外也有一个很好的演示粘性状态的工作。
我有同样的问题,这是我做了什么:我有一个在同一页面(没有Ajax)有多个视图的SPA,所以这是模块的代码:
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'}); }]);
我只有一个控制器的所有意见,但问题是一样的问题,控制器总是刷新数据,为了避免这种行为,我做了上面的人build议,我创build了一个服务,为此目的,然后通过它给控制器如下:
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); }; ... }]);
现在我可以从我的任何视图调用更新函数,传递值和更新我的模型,我没有必要使用HTML5 apis的持久性数据(这是在我的情况下,也许在其他情况下,将需要使用HTML5 apis像localstorage和其他的东西)。
解决scheme,将在这些范围内的多个作用域和多个variables
这个服务基于Anton的答案,但是更具扩展性,可以在多个范围内工作,并允许在同一范围内select多个范围variables。 它使用pathpath索引每个作用域,然后作用域variables名称索引更深一层。
使用此代码创build服务:
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; }]);
将此代码添加到您的应用程序模块中的运行function:
$rootScope.$on('$locationChangeStart', function (event, next, current) { $rootScope.$broadcast('savestate'); }); window.onbeforeunload = function (event) { $rootScope.$broadcast('savestate'); };
将restoreScope服务注入您的控制器(下面的示例):
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' } ]); }
上面的例子将初始化$ scope.user到存储的值,否则默认为提供的值并保存。 如果closures页面,刷新页面或更改路由,则所有已注册的作用域variables的当前值将被保存,并在下一次访问路由/页面时恢复。
服务的另一种select是使用价值存储。
在我的应用程序的基础上,我添加了这个
var agentApp = angular.module('rbAgent', ['ui.router', 'rbApp.tryGoal', 'rbApp.tryGoal.service', 'ui.bootstrap']); agentApp.value('agentMemory', { contextId: '', sessionId: '' } ); ...
然后在我的控制器中,我只是参考价值商店。 如果用户closures浏览器,我认为它不成立。
angular.module('rbAgent') .controller('AgentGoalListController', ['agentMemory', '$scope', '$rootScope', 'config', '$state', function(agentMemory, $scope, $rootScope, config, $state){ $scope.config = config; $scope.contextId = agentMemory.contextId; ...