我在网上查了几个解决方案,但我不太明白如何阻止控制器加载。所以,我已经创建了一个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;
}
]);
答案 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
同样,工厂可以进行更多重构,并消除一些代码,如缓存数据。这样,我们只去了一次工厂功能。