【问题标题】:Angularjs Best Practice for Data StoreAngularjs 数据存储最佳实践
【发布时间】:2015-10-16 01:27:24
【问题描述】:

我的 Angular 应用有 2 个控制器。我的问题是当用户离开页面时控制器不会保留数据。

如何将控制器上的选定数据存储到数据存储中,以便在其他控制器之间使用?

【问题讨论】:

    标签: javascript angularjs


    【解决方案1】:

    选项 1 - 自定义 service

    您可以利用专用的 Angular 服务在控制器之间存储和共享数据(services 是单实例对象)

    服务定义

     app.service('commonService', function ($http) {
    
            var info;
    
            return {
                getInfo: getInfo,
                setInfo: setInfo
            };
    
            // .................
    
            function getInfo() {
                return info;
            }
    
            function setInfo(value) {
                info = value;
            }
    });
    

    在多个控制器中的使用

    app.controller("HomeController", function ($scope, commonService) {
    
        $scope.setInfo = function(value){
            commonService.setInfo(value);
        };
    
    });
    
    
    app.controller("MyController", function ($scope, commonService) {
    
        $scope.info = commonService.getInfo();
    
    });
    

    选项 2 - html5 localStorage

    您可以使用内置的浏览器本地存储并从任何地方存储您的数据

    写作

    $window.localStorage['my-data'] = 'hello world';
    

    阅读

    var data = $window.localStorage['my-data']
    // ...
    

    选项 3 - 通过网络服务器 api

    如果你需要在不同用户之间持久化数据,你应该把它保存在服务器端的某个地方(db/cache)

    function getProfile() {
        return $http.get(commonService.baseApi + '/api/profile/');
    }
    
    function updateProfile(data) {
        var json = angular.toJson(data);
        return $http.post(commonService.baseApi + '/api/profile/', json);
    }
    

    【讨论】:

    • 要添加到本地存储方法,可以使用JSON.stringify(myData)将其存储为字符串并使用JSON.parse(localStorage['my-data')将其取回-stackoverflow.com/questions/3357553/…
    • 完全同意。甚至会推荐使用这个很棒的项目:github.com/grevory/angular-local-storage
    • 另一个选项是 ngStorage,它可以通过注入服务 $localStorage 和 $sessionStorage - github.com/gsklee/ngStorage
    • 感谢您的回复。如果我使用服务选项,控制器的 UI 如何知道何时更新其视图?此外,如果网格的数据源是一个数组,您是否会从添加到服务中的内容填充数组?
    • 同样,一旦用户完成选择,结果必须被发布回网络服务。
    【解决方案2】:

    要在同一页面上的两个控制器之间共享数据,您可以使用工厂/服务。以Share data between AngularJS controllers 为例。

    但是,如果这是跨页面重新加载/刷新,则需要将数据存储在本地存储中,然后在重新加载时读取。一个例子在这里:How do I store data in local storage using Angularjs?

    【讨论】:

      【解决方案3】:

      编辑参见Jossef Harush's 答案,他在其中写了一篇深入的回复,其中涵盖了包括此方法在内的其他方法。

      我建议使用 localStorage 或 sessionStorage - http://www.w3schools.com/html/html5_webstorage.asp

      HTML 本地存储提供了两个对象用于在客户端存储数据:

      • window.localStorage - 存储没有过期日期的数据
      • window.sessionStorage - 存储一个会话的数据(关闭浏览器选项卡时数据丢失)

      这假设您不想将数据 POST/PUT 到您的网络服务(您的问题中提到的 Windows 服务)。

      如果您的数据是数组或某种类型,您可以将其转换为 JSON 以存储为字符串,然后在需要时将其解析回如下 - How do I store an array in localStorage?:

      var names = [];
      names[0] = prompt("New member name?");
      localStorage["names"] = JSON.stringify(names);
      
      //...
      var storedNames = JSON.parse(localStorage["names"]);
      

      【讨论】:

      • 会话存储听起来很有趣。可以举个例子吗?
      • sessionStorage 的工作方式与 localStorage 完全一样。只需将localStorage['names'] 替换为sessionStorage['names']。唯一的区别是如上所述的到期日期。
      【解决方案4】:

      其他答案中没有提到一个选项(AFAIK)。

      活动

      • 您可以使用事件在控制器之间进行通信。

      • 这是一种无需中介的直接沟通 (如服务)并且不能被用户擦除(如 HTML 存储)。

      • 所有代码都编写在您尝试使用的控制器中 沟通,因此非常透明。

      下面是如何利用事件在控制器之间进行通信的一个很好的示例。

      发布者是想要发布的范围(换句话说,让其他人知道发生了什么事)。大多数人不关心发生了什么,也不是这个故事的一部分。

      订阅者是关心某个事件是否已发布的人(换句话说,当它收到通知时,嘿,这发生了,它会做出反应)。

      我们将使用 $rootScope 作为发布者和订阅者之间的中介这总是有效的,因为无论哪个范围发出事件,$rootScope 都是该范围的父级,或者parent of a parent of a parent.. 当 $rootScope 广播(告诉所有继承的人)一个事件时,每个人都会听到(因为 $rootScope 就是那个,范围继承树的根)所以应用程序中的每个其他范围都是一个孩子它或孩子的孩子的孩子..

      // publisher
      angular.module('test', []).controller('CtrlPublish', ['$rootScope','$scope',
          function ($rootScope, $scope) {
      
            $scope.send = function() {
              $rootScope.$broadcast('eventName', 'message');
            };
      
      }]);
      
      // subscriber
      angular.module('test').controller('ctrlSubscribe', ['$scope',
          function ($scope) {
      
            $scope.$on('eventName', function (event, arg) { 
              $scope.receiver = 'got your ' + arg;
            });
      
      }]);
      

      在上面我们看到两个控制器使用事件相互传递消息。事件有一个名称,它必须是唯一的,否则,订阅者不会区分事件。事件参数保存自动生成但有时有用的数据,消息是有效负载。在这个例子中,它是一个字符串,但它可以是任何对象。因此,只需将您希望通信的所有数据放入对象中并通过事件发送。

      注意:

      您可以避免为此使用根范围(并限制收到事件通知的控制器数量)如果两个范围位于直接继承行中彼此。下面进一步解释:

      $rootScope.$emit 只让其他 $rootScope 侦听器捕获它。当您不希望每个 $scope 都获得它时,这很好。主要是高层次的交流。把它想象成成年人在一个房间里互相交谈,这样孩子们就听不到他们的声音了。

      $rootScope.$broadcast 是一种让几乎所有东西都能听到的方法。这相当于父母大喊晚餐准备好了,所以房子里的每个人都听到了。

      $scope.$emit 是您希望 $scope 及其所有父级和 $rootScope 听到事件的时间。这是一个孩子在家里向父母抱怨(但不是在其他孩子可以听到的杂货店)。当您想与作为订阅者的子级或第 n 个子级的发布者进行通信时,可以使用此快捷方式。

      $scope.$broadcast 用于 $scope 本身及其子级。这是一个孩子对它的毛绒玩具耳语,这样他们的父母就听不到了。

      编辑:我认为 plunker 有一个更详细的例子就足够了,所以我决定在这里保持简单。这种详尽的解释应该会更好。

      【讨论】:

      • 这可能确实是一种在控制器之间共享数据的高效方法;但是,该示例不如公认的答案那么深入。如果您要创建一个这样的示例(使用某种获取和设置信息方法以及如何使用它们),那么我相信您的答案会得到更多的支持,并且社区会更好地理解这个概念。感谢您提及这种可能的实现方式。
      【解决方案5】:

      查看这个库https://www.npmjs.com/package/angularjs-store

      这可以帮助您更轻松地管理应用程序状态,因为它会强制您在应用程序上使用单向数据流。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-03-23
        • 1970-01-01
        • 1970-01-01
        • 2019-10-28
        • 2012-04-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多