[英]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.