获取从 angularJS 中的异步 $http 服务获得的对象,以便在 $scope 中全局访问

Posted

技术标签:

【中文标题】获取从 angularJS 中的异步 $http 服务获得的对象,以便在 $scope 中全局访问【英文标题】:Getting the object obtained from asynchronous $http service in angularJS to be accessible globally in $scope 【发布时间】:2015-07-27 03:24:23 【问题描述】:

我正在使用 Angular JS。我试图让使用 $http 服务获得的 json 对象可以在 $scope 变量中访问。在所有异步 AJAX ($http.get()) 调用中,如果我尝试打印存储在 $scope 变量中的数据并打印它,它会成功运行并向我显示预期的数据。但是在异步方法的范围之外,分配了数据的同一个 $scope 变量失去了对它的控制并打印出 undefined。

代码:

var app = angular.module('chariot', ['ngRoute', 'ngFileUpload']);
    app.factory('getTestcaseFactory', ['$http', '$routeParams', '$q', function($http, $routeParams, $q) 
       return 
              list: function()
                var deferred = $q.defer();
                $http.get('/testcase/' + $routeParams.testcase)
                .success(function(data, status, headers, config) 
                    deferred.resolve(data);
                )
                .error(function(data, status, headers, config) 
                    deferred.reject("Error fetching XML file: " + status + ' ' + JSON.stringify(headers));
                );
                return deferred.promise;
              
            ; 
    
    ]);
app.controller('testcaseCapCtrl', ['$scope', '$routeParams', '$http', 'getTestcaseFactory', function($scope, $routeParams, $http, getTestcaseFactory) 
    $scope.myjsonobj = '';
    var fetchTestcaseDetails = function() 
    getTestcaseFactory.list()
        .then(
            function(data) 
                $scope.xml.file = data;
                var x2js = new X2JS();
                var jsonObj = x2js.xml_str2json($scope.xml.file);
                $scope.xml.json = JSON.stringify(jsonObj, null, 2);
                $scope.model = jsonObj;
                console.log($scope.model);//PRINTS THE RIGHT DATA
            ,
            function(data) 
                alert(data);
            );
    
fetchTestcaseDetails();
console.log($scope.model); //Prints undefined
]);

【问题讨论】:

【参考方案1】:

到时候

console.log($scope.model);

执行,$http 请求尚未通过,这就是它打印未定义的原因。一旦$http 请求完成,您的$scope.model 将相应更新。您可以使用$timeout 进行测试

$timeout(function () 
    console.log($scope.model);
, 5000);

别忘了在你的控制器中注入$timeout

【讨论】:

虽然这个答案正确地指出了问题的本质,但 5000 超时是完全任意的,并且仅在某些时候有效,具体取决于实际调用需要多长时间。在回调中打印它,或者使用角度 $watch 机制使代码更面向数据,更少依赖时间。 感谢@Dan Moldovan!我也想通了可能是我必须使用计时器来等待 $http 服务完成并获得数据。 $timeout 完成这项工作。再次感谢! 很高兴帮助我的朋友! @doldt 你可以在这里分享一个 plunker 来展示你使用 $watch 解决这个问题的方法吗?在某处我看到了 $watch 方法,但我没有实施它来解决我的问题。 @SatyajitPatnaik 看到我的答案。【参考方案2】:

这可以节省我的时间! $timeout 进行救援。感谢@Dan Moldovan 的回答!由于 $http 服务是异步的,我们必须设置一个计时器来等待一个时间间隔,直到在 promise.success 部分中真正接收到数据,然后才能将其分配给 $scope 内的变量。

var app = angular.module('chariot', ['ngRoute', 'ngFileUpload']);
        app.factory('getTestcaseFactory', ['$http', '$routeParams', '$q', function($http, $routeParams, $q) 
           return 
                  list: function()
                    var deferred = $q.defer();
                    $http.get('/testcase/' + $routeParams.testcase)
                    .success(function(data, status, headers, config) 
                        deferred.resolve(data);
                    )
                    .error(function(data, status, headers, config) 
                        deferred.reject("Error fetching XML file: " + status + ' ' + JSON.stringify(headers));
                    );
                    return deferred.promise;
                  
                ; 
        
        ]);
    app.controller('testcaseCapCtrl', ['$scope', '$routeParams', '$timeout', 'getTestcaseFactory', function($scope, $routeParams, $timeout, getTestcaseFactory) 
        var fetchTestcaseDetails = function() 
        getTestcaseFactory.list()
            .then(
                function(data) 
                    $scope.xml.file = data;
                    var x2js = new X2JS();
                    var jsonObj = x2js.xml_str2json($scope.xml.file);
                    $scope.xml.json = JSON.stringify(jsonObj, null, 2);
                    $scope.model = jsonObj;
                    console.log($scope.model);//PRINTS THE RIGHT DATA
                ,
                function(data) 
                    alert(data);
                );
        
    fetchTestcaseDetails();
    $timeout(function() 
      console.log($scope.model); //Prints the Data now
    , 2000);
    ]);

【讨论】:

这不是一个好的解决方案,尽管它可能大部分时间都有效。请在下面查看我的答案。【参考方案3】:

到目前为止发布的解决方案根本上是错误的,因为它们依赖于任意超时,并且没有任何东西可以保证到那时异步答案可用。

正如我在上面的评论中所建议的,这里还有 2 个数据/事件驱动的解决方案。

    你要么只在回调函数中打印 (你已经在你的例子中这样做了) 或者,既然您无论如何都在使用 angular,您可以设置一个手表 (它在后台使用不太好的脏检查解决方案,但至少它从您的代码中抽象出来)

如果您想在数据可用后运行一个名为 processData 的函数,您已经在示例中执行的解决方案 1,请参阅此行:

console.log($scope.model);//PRINTS THE RIGHT DATA

在这里你可以调用任何其他函数来触发进程的继续,只要调用任何函数:

console.log($scope.model);//PRINTS THE RIGHT DATA
processData();

使用 Angular 的 $watch 机制(2.):

$scope.$watch(
    function()return $scope.model;,
    function(newValue, oldValue)
        if(newValue != null)
            console.log($scope.model);
            processData();
        
)

这将在异步回调后可用时打印数据,然后程序将继续处理。

【讨论】:

这很酷。我的第一种方法只是使用 $watch 方法。但后来我不知道究竟应该提到什么作为 watch 方法的第一个参数,所以我最终放弃了这种方法,而是采用了超时方法。无论如何,@doldt,感谢您的建议和帮助。我会立即实施。

以上是关于获取从 angularJS 中的异步 $http 服务获得的对象,以便在 $scope 中全局访问的主要内容,如果未能解决你的问题,请参考以下文章

angularjs $q$http 处理多个异步请求

如何从 angularjs 中的 JSONP 错误回调中获取数据?

Angularjs中$http.post返回的网页怎么获取某个元素的内容

AngularJs 中的两种方式数据绑定不使用异步回调

AngularJS:异步初始化过滤器

使用 AngularJS 从 JSON 响应中获取图像 url