在Angular JS中使用工厂和http

时间:2014-08-20 21:51:50

标签: javascript angularjs http factory

我刚刚开始使用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
});

5 个答案:

答案 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();
});

但是,这两种方法似乎都没有工厂来封装这么简单的查询吗?