在 AngularJS 中的视图之间切换时保持范围模型

IT技术 javascript angularjs
2021-01-27 07:47:18

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

当用户离开然后返回到view1,我如何确保以view1的形式输入的值不会被重置

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

6个回答

我花了一些时间来弄清楚这样做的最佳方法是什么。我还想保持状态,当用户离开页面然后按下后退按钮时,回到旧页面;而不仅仅是将我所有的数据放入rootscope

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

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

在服务中,我有一个模型。该模型只有数据 - 没有功能 -。这样它就可以从 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;
}]);

用户控制器示例

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

然后视图使用这样的绑定

<h1>{{user.model.name}}</h1>

而在应用module,运行函数中我处理的广播中的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 中开发时很常见的问题是相当的工程。

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

它确实跨视图持续存在,与您建议的方式完全相同,将其存储在服务中。有趣的是,它也会像您建议使用 window.onbeforeunload 一样,在页面更改中持续存在。谢谢你让我仔细检查。这个答案已经有一年多了,它似乎仍然是用 angular 做事的最简单方法。
2021-03-16 07:47:18
感谢您回到这里,即使它很旧:)。确保您的解决方案涵盖视图和页面,但没有解释哪些代码用于什么目的,并且还不够完整以至于无法使用我只是警告读者避免进一步的问题如果您有时间进行编辑以改进您的答案,那就太好了。
2021-03-17 07:47:18
:如果在你的控制器,而不是这个$scope.user = userService;,你有这样的事情:$scope.name = userService.model.name; $scope.email = userService.model.email;它会起作用还是改变视图中的变量不会在服务中改变它?
2021-03-26 07:47:18
这描述了如何在页面刷新时持久化数据,而不是在路由更改时如何持久化它,因此它没有回答问题。此外,它不适用于不使用路由的应用程序。此外,它没有显示sessionStorage.restoreState设置为 的位置"true"有关在页面刷新时保留数据的正确解决方案,请查看此处要在路线更改时保留数据,请查看 carloscarcamo 的答案。您所需要的只是将数据放入服务中。
2021-03-31 07:47:18
我认为 angular 缺乏针对这种常见事物的内置机制
2021-04-03 07:47:18

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

提琴手

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;
    }
}
我什至必须在页面导航(而不是页面刷新)之间执行此操作。这个对吗?
2021-03-20 07:47:18
我想我应该添加部分来完成这个答案,updateService应该在控制器被破坏时调用 - $scope.$on('$destroy', function() { console.log('Ctrl destroyed'); $scope.updateServiceName($scope.name); });
2021-04-09 07:47:18

$rootScope 是一个很大的全局变量,它适用于一次性事物或小型应用程序。如果您想封装您的模型和/或行为(并可能在其他地方重用它),请使用服务。除了提到的 OP 的 google group 帖子之外,另请参阅https://groups.google.com/d/topic/angular/eegk_lB6kVs/discussion

Angular 并没有真正提供你正在寻找的开箱即用的东西。我会做些什么来完成你所追求的是使用以下附加组件

UI 路由器UI 路由器附加功能

这两个将为您提供基于状态的路由和粘性状态,您可以在状态之间切换,所有信息都将保存为范围“保持活动”可以这么说。

检查两者的文档,因为它非常简单,ui router extras 也很好地演示了粘性状态的工作原理。

我已经阅读了文档,但找不到如何在用户单击浏览器后退按钮时保留表单输入。你能指出我的具体情况吗?谢谢!
2021-04-01 07:47:18

我遇到了同样的问题,这就是我所做的:我在同一页面中有一个具有多个视图的 SPA(没有 ajax),所以这是module的代码:

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

现在我可以从我的任何视图调用更新函数,传递值并更新我的模型,我不需要使用 html5 apis 来持久化数据(这在我的情况下,也许在其他情况下需要使用 html5 apis 像 localstorage 和其他东西)。

是的,就像一个魅力。我们的数据工厂已经编码,我使用 ControllerAs 语法,所以我将它重写为 $scope 控制器,以便 Angular 可以控制它。实施非常简单。这是我编写的第一个 Angular 应用程序。tks
2021-03-17 07:47:18