简体   繁体   English

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

[英]Angularjs: load data in service then load it to controllers

I've checked several solutions on the web but I don't quite understand how to stop the controllers from loading. 我在网上查了几个解决方案,但我不太明白如何阻止控制器加载。 So, I've created a plunkr to highlight what I want to do. 所以,我已经创建了一个plunkr来突出我想要做的事情。

Basically: I want to load all data in a service and then pass around that data from that service to each controller. 基本上:我想加载服务中的所有数据,然后将该数据从该服务传递到每个控制器。 When the app first loads, because it's Async, the controllers are loaded first. 当应用程序首次加载时,因为它是Async,所以首先加载控制器。

I could have just used the factory in each controller, but I want to hold that data in the "allProducts" property of the service. 我本可以在每个控制器中使用工厂,但我希望将该数据保存在服务的“allProducts”属性中。 I don't see the need to call the factory function each time a view loads. 我没有看到每次加载视图时都需要调用工厂函数。

In the example, I've also tried with the $q service, but seems to me it has the same behaviour just like the http from the factory and still needs to call the http request on each view load... 在这个例子中,我也尝试过使用$ q服务,但在我看来,它具有与工厂中的http相同的行为,并且仍然需要在每个视图加载时调用http请求...

So, could somebody help me with this example and implement an elegant solution? 那么,有人可以帮我解决这个例子并实现一个优雅的解决方案吗?

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 here: http://plnkr.co/edit/ZvtYwXHSasC3fCAZKkDF?p=preview plunkr: http ://plnkr.co/edit/ZvtYwXHSasC3fCAZKkDF?p = preview

I didn't actually test it, but looks like you need to create and return a promise in order to have the data returned when it's available. 我实际上没有测试它,但看起来你需要创建并返回一个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;
    }
]);

Check this: http://plnkr.co/edit/ey0na3l2lyT0tUdbDyrf?p=preview 检查一下: http//plnkr.co/edit/ey0na3l2lyT0tUdbDyrf?p = preview

Changes: 变化:
- a main app controller that wraps all your app. - 包装所有应用程序的主应用程序控制器。
In this controller we prevent route change if the boot hasn't finished all its jobs. 在此控制器中,如果引导尚未完成所有作业,我们会阻止路由更改。 When boot is finished, we change location to the main/default route. 启动完成后,我们将位置更改为主/默认路由。
- in our run block we set the bootStatus var to false and wait until products are fetch. - 在我们的run块中,我们将bootStatus var设置为false并等待产品被提取。

Also, I've stored the result from service to $rootScope so you can use that data in all your controllers without injecting the service over and over again. 此外,我已将服务的结果存储到$rootScope因此您可以在所有控制器中使用该数据,而无需反复注入服务。

FINALLY!!! 最后!!! I Managed to do what I was looking for. 我管理做我想要的。

Note, this is not necessarily a best practice, but it was a problem that was bugging me and wanted to know how it's done. 请注意,这不一定是最佳做法,但这是一个困扰我的问题,并想知道它是如何完成的。

The way I did it was to create a global variable, where I use a main resolve function to wait for the factory to do the http get and then pass it to the service. 我这样做的方法是创建一个全局变量,我使用main resolve函数等待工厂执行http get,然后将其传递给服务。 Then, I use resolve on every state where I need that data and reference that function. 然后,我在需要该数据的每个状态上使用resolve并引用该函数。

UPDATE: Realized that I was calling the same factory function each time the state was changins, so I decided to go with a variable - a property in the appService which turns to true when the http get was called once: appService.retrieved and changed the main resolve function a bit. 更新:实现每次状态变化时我都调用相同的工厂函数,所以我决定使用变量 - 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;
}]

And in the state 而在州

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

You can find the plnkr with the working solution, here: http://plnkr.co/edit/ZvtYwXHSasC3fCAZKkDF?p=preview 您可以在这里找到带有工作解决方案的plnkr: http ://plnkr.co/edit/ZvtYwXHSasC3fCAZKkDF?p = preview

Again, the factory could be refactored some more and eliminate some code like the caching data. 同样,工厂可以进行更多重构,并消除一些代码,如缓存数据。 This way, we only go once to the factory function. 这样,我们只去了一次工厂功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM