Javascript 在AngularJS中更改视图时维护范围模型

Javascript 在AngularJS中更改视图时维护范围模型,javascript,angularjs,Javascript,Angularjs,我正在学习AngularJS。假设/view1使用My1Ctrl,而/view2使用My2Ctrl;可以使用选项卡导航到,其中每个视图都有自己的简单但不同的形式 当用户离开并返回view1时,如何确保以view1形式输入的值不会重置 我的意思是,第二次访问view1时,如何保持与我离开时完全相同的模型状态?$rootScope是一个大的全局变量,对于一次性的东西或小型应用程序来说,这很好。 如果您想封装您的模型和/或行为(并可能在其他地方重用),请使用服务。除了上面提到的谷歌集团帖子,另请参见。

我正在学习AngularJS。假设/view1使用My1Ctrl,而/view2使用My2Ctrl;可以使用选项卡导航到,其中每个视图都有自己的简单但不同的形式

当用户离开并返回view1时,如何确保以view1形式输入的值不会重置


我的意思是,第二次访问view1时,如何保持与我离开时完全相同的模型状态?

$rootScope是一个大的全局变量,对于一次性的东西或小型应用程序来说,这很好。
如果您想封装您的模型和/或行为(并可能在其他地方重用),请使用服务。除了上面提到的谷歌集团帖子,另请参见。

我花了一点时间研究出最好的方法是什么。我还想保持状态,当用户离开页面,然后按下后退按钮,返回到旧页面;而不仅仅是把我所有的数据放进根范围

最终的结果是为每个控制器提供一个服务。在控制器中,如果清除了函数和变量,您就不关心它们

控制器的服务通过依赖项注入进行注入。由于服务是单例的,它们的数据不会像控制器中的数据那样被破坏

在服务中,我有一个模型。模型只有数据-没有函数-。这样,它就可以从JSON来回转换来持久化它。我使用html5本地存储进行持久化

最后,我使用了
window.onbeforeunload
$rootScope.$broadcast('saveState')
让所有服务知道它们应该保存状态,
$rootScope.$broadcast('restoreState')
让它们知道恢复状态(用于用户离开页面并分别按下后退按钮返回页面时)

myuserController的名为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;
}]);
用户控制器示例

function userCtrl($scope, userService) {
    $scope.user = userService;
}
然后视图使用如下绑定

<h1>{{user.model.name}}</h1>
正如我提到的,这需要一段时间才能达到这一点。这是一种非常干净的方法,但是做一些我认为在开发过程中非常常见的问题是一个相当大的工程


我希望看到更简单,但作为处理跨控制器保持状态的干净方法,包括当用户离开并返回页面时。

回答有点晚,但只是更新了一些最佳实践


我也有同样的问题,我就是这么做的: 我有一个SPA,在同一个页面中有多个视图(没有ajax),因此模块的代码如下:

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'});
}]);
对于所有视图,我只有一个控制器,但是,问题与问题相同,控制器总是刷新数据,为了避免这种行为,我按照上面的建议做了,并为此创建了一个服务,然后将其传递给控制器,如下所示:

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);
    };
    ...
}]);

现在我可以从任何视图调用update函数,传递值并更新模型,我不需要使用HTML5API来获取持久性数据(在我的情况下,可能在其他情况下需要使用HTML5API,如localstorage和其他东西)。

Angular并没有真正提供您想要的现成的东西。我要做的是使用以下附加组件来完成您所追求的目标

&

这两个选项将为您提供基于状态的路由和粘性状态,您可以在状态之间切换,所有信息都将保存为作用域“保持活动状态”


查看这两个方面的文档,因为它非常简单,ui router extras还很好地了解了粘性状态的工作原理。

解决方案将适用于多个范围和这些范围内的多个变量。

该服务基于Anton的回答,但更具可扩展性,可以跨多个范围工作,并允许在同一范围内选择多个范围变量。它使用路由路径为每个作用域编制索引,然后使用作用域变量名为更深一层编制索引

使用此代码创建服务:

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;
}]);
$rootScope.$on('$locationChangeStart', function (event, next, current) {
    $rootScope.$broadcast('savestate');
});

window.onbeforeunload = function (event) {
    $rootScope.$broadcast('savestate');
};
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' }
    ]);
}
将此代码添加到应用程序模块中的跑步功能中:

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;
}]);
$rootScope.$on('$locationChangeStart', function (event, next, current) {
    $rootScope.$broadcast('savestate');
});

window.onbeforeunload = function (event) {
    $rootScope.$broadcast('savestate');
};
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' }
    ]);
}
将restoreScope服务注入控制器(以下示例):

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;
}]);
$rootScope.$on('$locationChangeStart', function (event, next, current) {
    $rootScope.$broadcast('savestate');
});

window.onbeforeunload = function (event) {
    $rootScope.$broadcast('savestate');
};
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初始化为存储值,否则将默认为提供的值并将其保存为关闭。如果页面已关闭、刷新或路由已更改,则所有已注册范围变量的当前值都将保存下来,并在下次访问路由/页面时恢复。

服务的替代方法是使用值存储

在我的应用程序的底部,我添加了这个

var agentApp = angular.module('rbAgent', ['ui.router', 'rbApp.tryGoal', 'rbApp.tryGoal.service', 'ui.bootstrap']);

agentApp.value('agentMemory',
    {
        contextId: '',
        sessionId: ''
    }
);
...
然后在我的控制器中,我只引用值存储。我认为如果用户关闭浏览器,它就不起作用了

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

$scope.config = config;
$scope.contextId = agentMemory.contextId;
...

您可以使用
$locationChangeStart
事件将以前的值存储在
$rootScope
或服务中。当您返回时,只需初始化所有以前存储的值。下面是一个使用
$rootScope
的快速演示

var-app=angular.module(“myApp”、“ngRoute”);
应用程序控制器(“tab1Ctrl”,函数($scope,$rootScope){
if($rootScope.savedScopes){
for(输入$rootScope.savedScopes){
$scope[key]=$rootScope.savedScopes[key];
}
}
$scope.$on(“$locationChangeStart”,函数(事件、下一个、当前){
$rootScope.savedScopes={
名称:$scope.name,
年龄:$scope.age
};
});
});
应用控制器(“tab2Ctrl”,功能($scope){
$scope.language=“英语”;
});
app.config(函数($routeProvider){
$routeProvider
.当(“/”时{
模板:“Tab1 contentName:

Age:填写详细信息并单击Tab2”, 控制器:“tab1Ctrl” }) .when(“/tab2”{