我刚刚开始使用angular,看到你可以定义一个工厂用于多个控制器。
我有下面的代码,它会在'success'方法中返回我的结果。但不是在功能之外。
我感觉它与异步相关,但我不太确定如何继续它,如果是这样的话。
任何帮助将不胜感激,所以谢谢你提前。
var abyssApp = angular.module('abyssApp', []);
abyssApp.factory('abyssData', function($http) {
var result,
products = $http.get('http://abyss.local/products.php');
products.success(function(data) {
result = angular.fromJson(data);
console.log('success: ', result); // object with data in
});
console.log(result); // undefined
});
abyssApp.controller('ItemListCtrl', function($scope, abyssData) {
$scope.items = abyssData;
console.log('abyssData: ', abyssData); // undefined
});
答案 0 :(得分:4)
以下是一些编辑。请注意,我在没有真正检查的情况下这样做,所以类型和错误是完全可能的,但它的要点应该是有道理的。
var abyssApp = angular.module('abyssApp', []);
abyssApp.service('abyssData', function($http) {
this.products = $http.get('http://abyss.local/products.php');
});
abyssApp.controller('ItemListCtrl', function($scope, abyssData) {
abyssData.products.then(function(data) {
console.log(data);
$scope.items = data;
}).catch(function(err){console.log(err);});
});
我把它变成了服务而不是工厂,因为你真的只需要一个服务(单身)。如果您要调用不同的网址,并希望执行product = new abyssData('potatoes')
之类的操作,那么工厂就是合适的。
一般来说,$ http会返回一个 promise 对象,该对象本身不是您需要的数据,而是解析到您需要的数据。这种承诺模式在角度上重复了很多(并且在其他javascript场所越来越受欢迎,因为它很棒(IMO))。这意味着,在promise对象上,您调用.then()方法并传入一个函数,以便在解析promise时调用它。 $ http解析XHR的结果。其他承诺可以解决其他问题。
在promise .then stack结束时,放入.catch()调用是一种很好的形式,因为在promise中抛出的异常通常会进入bitbucket,除非你明确地查找它们。它是承诺工作方式的一般缺陷,意味着你必须小心例外。使用较旧的JS引擎,您需要将其更改为.then()'catch',因为catch在某些地方是一个有趣的词。但我90%肯定任何在.catch上窒息的JS环境都不会运行角度。
答案 1 :(得分:2)
在'ItemListCtrl'中你应该注入从'abyssData'工厂创建的对象。然后,它应该返回$ http promise并直接在控制器中,在成功回调中,您应该将返回的结果分配给$ scope.items。这只是一个示例性的方法,在Angular中有很多方法和模式可以解决这些问题。
console.log(result); // undefined
记录'未定义',因为当您调用此行时,尚无响应。试着弄清楚,承诺是什么以及AJAX调用的确切方式,特别是应该定义“成功”和“错误”。
答案 2 :(得分:1)
你反过来了。首先,工厂应该返回一个值。该值为单例。这意味着在工厂执行后,它不会多次执行。你可以做的是返回一个对你的结果有参考的对象。
abyssApp.factory('abyssData', function($http) {
var ret = {},
products = $http.get('http://abyss.local/products.php')
products.success(function(data) {
ret.result = angular.fromJson(data);
console.log('success: ', result); // object with data in
});
console.log(result); // undefined
return ret;
});
abyssApp.controller('ItemListCtrl', function($scope, abyssData) {
$scope.items = abyssData.result;
console.log('abyssData: ', abyssData); // undefined
});
但事件这个解决方案并没有很好的味道。除非您的对象列表永远不会更新。返回可在需要时查询的资源会更有意义。不确定控制器何时加载,结果将被加载。这意味着访问abyssData.result
可能会先返回undefined
,然后再返回其他内容。
但说实话,你应该做的是:
https://docs.angularjs.org/api/ngResource/service/ $资源
你可以拥有这样的工厂:
abyssApp.factory('AbyssData', ['$resource', function($resource) {
return $resource('http://abyss.local/products.php')
}])
abyssApp.factory('abyssData', ['AbyssData', function(AbyssData) {
return AbyssData.query();
}])
检查一下:https://docs.angularjs.org/api/ngResource/service/ $ resource
答案 3 :(得分:1)
可能有三件事:
1)声明依赖项显式:
abyssApp.controller('ItemListCtrl', function($scope, abyssData) {
的
abyssApp.controller('ItemListCtrl', ['$scope', 'abyssData', function($scope, abyssData) {
2)要使用你想要的值,工厂必须返回该值,所以最后你应该返回"结果"变量。 尝试更改"结果"这是 xhr 请求中的常见变量名,以防止覆盖。
3)为了防止在返回之前访问数据,请尝试给出方法而不是值:
abyssApp.factory('abyssData', function($http) {
return {
get: function(successCallback){ //your callback function
$http.get('http://abyss.local/products.php')
.success(function(){
if(successCallback){
successCallback.apply(arguments);
}
});
}
}
}
使用更改:
$scope.items = abyssData;
对于此
abyssData.get(function(data){
$scope.items = data;
});
答案 4 :(得分:1)
您需要从工厂公开一些数据或方法,以便控制器可以访问它。目前工厂没有任何暴露。
根据您的使用情况,我会建议这样的事情:
var abyssApp = angular.module('abyssApp', []);
abyssApp.factory('abyssData', function($http) {
function abyssData() {
var self = this;
self.products = null;
self.getProducts = function(){
// return products if they are set already (cache)
if (self.products) { return self.products; }
$http.get('http://abyss.local/products.php').success(function(data){
self.products = data;
return self.products;
});
};
}
return new abyssData();
});
abyssApp.controller('ItemListCtrl', function($scope, abyssData) {
$scope.items = abyssData.getProducts();
});
但是,这两种方法似乎都没有工厂来封装这么简单的查询吗?