Angularjs:在服务中加载数据然后将其加载到控制器

时间:2016-02-17 07:54:05

标签: javascript angularjs service controller factory

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

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

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

在这个例子中,我也尝试过使用$ q服务,但在我看来,它具有与工厂中的http相同的行为,并且仍然需要在每个视图加载时调用http请求... < / p>

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

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

plunkr:http://plnkr.co/edit/ZvtYwXHSasC3fCAZKkDF?p=preview

3 个答案:

答案 0 :(得分:2)

我实际上没有测试它,但看起来你需要创建并返回一个promise,以便在数据可用时返回数据。

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

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:0)

最后!!!我管理做我想要的。

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

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

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

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

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