【问题标题】:Angularjs: load data in service then load it to controllersAngularjs:在服务中加载数据然后将其加载到控制器
【发布时间】:2016-02-17 07:54:05
【问题描述】:

我在网上查了几个解决方案,但我不太明白如何阻止控制器加载。所以,我创建了一个 plunkr 来突出我想要做的事情。

基本上:我想将所有数据加载到服务中,然后将该数据从该服务传递到每个控制器。当应用第一次加载时,因为它是异步的,所以首先加载控制器。

我本可以在每个控制器中使用工厂,但我想将该数据保存在服务的“allProducts”属性中。我不认为每次加载视图时都需要调用工厂函数。

在示例中,我也尝试过使用 $q 服务,但在我看来,它的行为与出厂时的 http 相同,并且仍然需要在每次视图加载时调用 http 请求...

那么,有人可以帮助我完成这个示例并实现一个优雅的解决方案吗?

app.factory('productsFactory', ['$http', '$q',
    function($http, $q) {
        var cachedData; //here we hold the data after the first api call  
        function getData(callback) {
            if (cachedData) {
                callback(cachedData);
            } else {
                $http.get('http://api.bestbuy.com/v1/products(longDescription=iPhone*|sku=7619002)?show=sku,name&pageSize=15&page=5&apiKey=bqs7a4gwmnuj9tq6bmyysndv&format=json')
                    .success(function(data) {
                        cachedData = data; //caching the data in a local variable
                        callback(data);
                    });
            }
        }

        return {
            getProds: getData
        }
    }
])

app.service('appService', ['productsFactory', '$q',
    function(productsFactory, $q) {
        var _this = this;
        productsFactory.getProds(function(data) {
            _this.allProducts = data; //wait for data to load before loading the controllers
        })

    }
])

app.controller('productsCtrl', ['$scope', 'appService',
    function($scope, appService) {
        $scope.myProducts = appService.allProducts;
    }
]);

请戳这里:http://plnkr.co/edit/ZvtYwXHSasC3fCAZKkDF?p=preview

【问题讨论】:

  • 谢谢,鲍勃。是的,我知道那个实现,尽管在控制器中调用 productsFactory.getProds(function(data){$scope.myProducts = data}) 的代码会更少,而无需通过服务 - 我的兴趣是是否有解决方案只调用一次 http 请求,在服务和将数据保存在变量中,然后将其传递给控制器​​。谢谢

标签: javascript angularjs service controller factory


【解决方案1】:

我实际上并没有对其进行测试,但看起来您需要创建并返回一个承诺,以便在数据可用时返回它。

    app.factory('productsFactory', ['$http', '$q',
    function($http, $q) {

        var cachedData; //here we hold the data after the first api call  
        function getData(callback) {
var d = $q.defer();
            if (cachedData) {
d.resolve(callback(cachedData));

            } else {
                $http.get('http://api.bestbuy.com/v1/products(longDescription=iPhone*|sku=7619002)?show=sku,name&pageSize=15&page=5&apiKey=bqs7a4gwmnuj9tq6bmyysndv&format=json')
                    .success(function(data) {
                        cachedData = data; //caching the data in a local variable
                        d.resolve(callback(cachedData));
                    });
            }
return d.promise;
        }

        return {
            getProds: getData
        }
    }
])

app.service('appService', ['productsFactory', '$q',
    function(productsFactory, $q) {
        var _this = this;
        productsFactory.getProds(function(data) {
            _this.allProducts = data; //wait for data to load before loading the controllers
        })

    }
])

app.controller('productsCtrl', ['$scope', 'appService',
    function($scope, appService) {
        $scope.myProducts = appService.allProducts;
    }
]);

【讨论】:

    【解决方案2】:

    检查这个:http://plnkr.co/edit/ey0na3l2lyT0tUdbDyrf?p=preview

    变化:
    - 一个包含所有应用的主应用控制器。
    在此控制器中,如果引导尚未完成所有工作,我们会阻止路由更改。启动完成后,我们将位置更改为主/默认路由。
    - 在我们的run 块中,我们将bootStatus var 设置为false 并等到获取产品。

    此外,我已将服务的结果存储到 $rootScope,因此您可以在所有控制器中使用该数据,而无需一遍又一遍地注入服务。

    【讨论】:

      【解决方案3】:

      终于!!!我设法做我正在寻找的东西。

      请注意,这不一定是最佳实践,但这是一个困扰我的问题,我想知道它是如何完成的。

      我这样做的方式是创建一个全局变量,在其中我使用主解析函数等待工厂执行 http get 然后将其传递给服务。然后,我对需要该数据的每个状态都使用 resolve 并引用该函数。

      更新:意识到每次状态改变时我都在调用同一个工厂函数,所以我决定使用一个变量 - appService 中的一个属性,当 http get 被调用一次时它变为 true:appService.retrived并稍微改变了主要的解析功能。

      var mainResolve = ['$q', 'appService', 'productsFactory', function($q, appService, productsFactory) {
      var defer = $q.defer();
      if(appService.retrieved) {
          defer.resolve();
      } else {
        productsFactory.getProds(function(data) {
            appService.allProducts = data;
            defer.resolve();
        })
        appService.retrieved = true;
      }
      
      return defer.promise;
      }]
      

      并且在状态

      .state('home', {
        url: "/home",
        templateUrl: "home.html",
        controller: 'homeCtrl',
        resolve: {
          waitingFor: mainResolve
        }
      })
      

      您可以在此处找到具有有效解决方案的 plnkr:http://plnkr.co/edit/ZvtYwXHSasC3fCAZKkDF?p=preview

      同样,工厂可以进行更多重构并消除一些代码,例如缓存数据。这样,我们只去工厂函数一次。

      【讨论】:

        猜你喜欢
        • 2012-09-21
        • 1970-01-01
        • 2015-02-17
        • 2013-08-30
        • 2016-04-29
        • 2015-01-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多