如何处理来自$ http的响应,返回一个promise并绑定到AngularJS中的结果?

时间:2014-04-18 12:30:18

标签: javascript angularjs promise

我正在使用AngularJS 1.2.6

我正在使用$http.get()拨打电话。我想在服务中处理响应以保持控制器清洁,然后只返回相关数据。我认为我可以直接绑定到promise,当异步调用完成后,$scope对象上的属性将会更新,这将自动更新我的视图。

在这个例子中,我正在调用Encyclopedia of Life API来获取多媒体对象列表。我只对图像感兴趣(总是用mimeType: 'image/jpeg'返回),这样我就可以将它们输入到图像轮播指令中。

注意:我遗漏了长网址以减少混乱

服务

.factory('GetEOL', ['$http', function ($http) {

    var getPhotoList = function ( eolCode ) {

        // Call API that returns multimedia objects
        var promise = $http.jsonp( 'someURL' + eolCode ).then(function (response) {
            var media = response.data.dataObjects, // array returned from api
                slides = [];

            // Grab only the images from the API response
            _.each(media, function(item) {
                if (item.mimeType === 'image/jpeg') {
                    slides.push({
                        image: item.eolMediaURL,
                        text: item.rightsHolder
                    });
                }
            });
            return slides;
        });
        return promise;
    };
    return {
        getPhotoList: getPhotoList
    };
}]);

控制器:

.controller('ProfileImageController', ['$scope', 'GetEOL', function ($scope, GetEOL, SpeciesCodes) {
    $scope.codes = {eol: 1019149};
    $scope.slides = [];
    $scope.interval = 5000;


    // Shouldn't this automatically update my view when the promise is fulfilled??
    $scope.slides = GetEOL.getPhotoList($scope.codes.eol);
}]);

查看:

<div class="col-md-3 thumbnail eol-slider">
    <carousel interval="interval"> <!-- angular-ui-bootstrap directive -->
        <slide ng-repeat="slide in slides" active="slide.active">
            <img ng-src="{{slide.image}}" style="margin:auto;">
            <div class="carousel-caption">
                <p>{{slide.text}}</p>
            </div>
        </slide>
    </carousel>
</div>

2 个答案:

答案 0 :(得分:3)

  

当履行承诺时,不应该自动更新我的观点吗?

不,不再是Angular 1.2,它被认为太神奇了,所以现在你必须明确指定延续:

GetEOL.getPhotoList($scope.codes.eol).then(function(result){
        $scope.slides = result;
});

引用IgorMinar的变化:

  

以前承诺在表达式中的表达式中的任何位置找到   评估将在未解决时评估为未定义且未评估   履行价值,如果履行。

     

这个功能并没有被证明是非常有用或受欢迎的,   主要是因为模板中数据访问之间的二分法   (作为原始值访问)和控制器代码(作为承诺访问)。

     

在大多数代码中,我们最终在控制器中手动解析promises   或者通过这种方式自动路由和统一模型访问。

     

自动承诺展开的其他缺点:

     
      
  • 在构建组件时,通常需要接收原始承诺
  •   
  • 增加了复杂性并减慢了表达式评估
  •   由于需要生成的代码量,
  • 使表达式代码预生成不具吸引力
  •   
  • 使IDE自动完成并支持工具支持
  •   
  • 添加了太多魔法
  •   

在1.2中,您仍然可以选择加入。您只需告诉$parseProvider

$parseProvider.unwrapPromises(true)

它会像Angular 1.1那样做。

您也可以直接从服务中复制此内容而无需展开角度模板:

  • 返回一个空数组,在服务中保留对它的引用
  • 当promise解析时 - 填充该数组,因为数组是通过引用传递的,所以它也会在范围内更改它。
  • 您还可以向数组中添加.then方法(为其分配与承诺相同的值),这样它就可以自行调整,但不确定我是否非常喜欢这个想法。

这是一个非常简单的实现:

var app = angular.module('app',[]);

app.controller("TestCtrl", function ($scope,MyService) {
    $scope.items = MyService();
});
app.service("MyService",function($timeout){
    return function getResource(){
        var dat = [];
        $timeout(function(){
            dat.push("Hello"); // Note, DO NOT do `dat = something` here, that will break
            dat.push("World"); // you must change _the same reference_
        },2000);
        return dat;    
    }
});

(fiddle)

或者,如果你返回一个可用的 - 它看起来像:

dat.then = t.then.bind(t); // add promise methods
dat.catch = t.catch.bind(t);
dat.finally = t.catch.bind(t);

然后:

var result = MyService();
$scope.items = result;
result.then(function(){
    alert("Also hooked on promise completion!"); 
});

(fiddle)

答案 1 :(得分:0)

A)

$scope.slides = [];
GetEOL.getPhotoList($scope.codes.eol).then(function(result){
    $scope.slides = result;
});

B)使用https://github.com/mgonto/restangular