AngularJS $http.get().then和绑定到列表

50

我有一个看起来像这样的列表:

<li ng-repeat="document in DisplayDocuments()" ng-class="IsFiltered(document.Filtered)">
    <span><input type="checkbox" name="docChecked" id="doc_{{document.Id}}" ng-model="document.Filtered" /></span>
    <span>{{document.Name}}</span>
</li>
我在控制器中将这个列表绑定到这里:
$scope.Documents = $http.get('/Documents/DocumentsList/' + caseId).then(function(result) {
    return result.data;
});

当代码运行时,我没有得到任何结果。当我删除then方法时,我得到三个空行,计数正确,但没有显示任何信息。

我知道“所有其他东西”都可以正常工作,因为我之前使用jQuery填充了列表,我做错了什么?

这是服务器的响应:

{Id:3f597acf-a026-45c5-8508-bc2383bc8c12, Name:ZZ_BL0164_Skisse BL0164_945111.pdf, Order:1,…}
{Id:46f51f1f-02eb-449a-9824-8633e8ae7f31, Name:ZB_BL0201_Firmaattest BL0201_945111.pdf, Order:1,…}
{Id:fddd1979-c917-4b32-9b83-b315f66984ed, Name:ZA_BL0228_Legitimasjonsskjema BL0228_945111.pdf,…}

我通常使用.get(...).success(function (data) {});,也许你可以添加console.log(result)并查看它输出了什么?我还会确保您调用的URL格式正确。caseId是什么? - Eduard Gamonal
1
我也尝试过那种方式,只是觉得这种方式看起来更好,更容易理解,所以想尝试一下。我见过有人都用这两种方式,但我无法让这种方式工作。 - ruffen
你正在将 Document 绑定到你的作用域,但在 ng-repeat 中使用 DisplayDocuments(),那么 DisplayDocuments() 是从哪里来的? - Mark Coleman
我在工厂里做类似的事情。但是,我使用的不是$scope.Documents,而是var mypromise,并且我在then/success部分设置了$scope.Documents - Eduard Gamonal
我有一个应该返回文档的服务,这就是为什么我想避免在then/success部分设置$scope.documents,但看起来我必须做类似的事情。 - ruffen
4个回答

54
$http方法返回一个Promise,它无法被迭代,因此您必须通过回调将结果附加到作用域变量中:

$http methods 返回一个 promise ,不能被迭代,所以你需要通过回调函数将结果附加到作用域变量中:

$scope.documents = [];
$http.get('/Documents/DocumentsList/' + caseId)
  .then(function(result) {
    $scope.documents = result.data;
});

现在,由于这个代码只在获取结果后才定义了documents变量,所以您需要在之前初始化documents变量的作用域:$scope.documents = []。否则,你的ng-repeat指令会出错。

这样,ng-repeat指令将首先返回一个空列表,因为一开始documents数组是空的,但是一旦接收到结果,ng-repeat指令将再次运行,因为`documents`已经在成功回调中发生了更改。

另外,您可能希望修改ng-repeat表达式为:

<li ng-repeat="document in documents" ng-class="IsFiltered(document.Filtered)">

因为如果你的DisplayDocuments()函数向服务器发出了调用请求,那么由于$digest周期的影响,这个调用将会被执行多次。


所以,只有在不返回数组时,我才能返回一个作用域的 promise?Displaydocuments 不会调用服务器,不过还是感谢提醒。 - ruffen
1
我的意思是,如果你写了 $scope.documents = $http.get(...) 那么 documents 将引用一个 promise(来自 $q 服务),因为 $http 服务返回的就是一个 promise。 - Stewie
3
明白了,但我原本以为Angular能够自动解析那个Promise呢?显然我错了。 - ruffen
你可能将$http服务误认为是$resource,后者确实返回一个(迭代)承诺,但当结果返回时,该承诺会自动解决。 - Stewie
说实话,我之前不知道$resource,但它看起来正是我需要的。谢谢! - ruffen
我被这个问题困扰了两个小时,感谢你的回答。 - Naguib Ihab

26

$http 返回的 Promise 不能直接绑定(我不确定为什么)。 我使用包装服务,对我来说非常完美:

.factory('DocumentsList', function($http, $q){
    var d = $q.defer();
    $http.get('/DocumentsList').success(function(data){
        d.resolve(data);
    });
    return d.promise;
});

然后在控制器中将其绑定:

function Ctrl($scope, DocumentsList) {
    $scope.Documents = DocumentsList;
    ...
}

更新!:

在Angular 1.2中取消了自动展开承诺。请参见http://docs.angularjs.org/guide/migration#templates-no-longer-automatically-unwrap-promises


我还不太确定具体是怎么做到的,但是哇,你解除了我的痛苦。谢谢! - Davion
对于@Davion和其他想知道这段代码是干什么的人,$http返回一个HTTP承诺,它包装了响应对象而不是实际数据。这就是为什么你不能直接"绑定"它的原因。在这里,$q服务被用来创建一个新的承诺,并将其解析为实际数据。通过操作这个承诺,控制器可以获取到实际数据而不仅仅是HTTP响应。顺便说一句,$http的_success_和_error_方法已经过时了,所以现在推荐使用_then_方法。 - BitMask777

6

实际上,你可以在 $http.get 上得到一个 promise

尝试使用以下流程:

<li ng-repeat="document in documents" ng-class="IsFiltered(document.Filtered)">
    <span><input type="checkbox" name="docChecked" id="doc_{{document.Id}}" ng-model="document.Filtered" /></span>
    <span>{{document.Name}}</span>
</li>

其中documents是您的数组。

$scope.documents = [];

$http.get('/Documents/DocumentsList/' + caseId).then(function(result) {
    result.data.forEach(function(val, i) { 
        $scope.documents.push(/* put data here*/);
    });
}, function(error) {
    alert(error.message);
});                       

1
尝试使用success()回调函数。
$http.get('/Documents/DocumentsList/' + caseId).success(function (result) {
    $scope.Documents = result;
});

但现在由于Documents是一个数组而不是一个Promise,所以请删除()
<li ng-repeat="document in Documents" ng-class="IsFiltered(document.Filtered)"> <span>
           <input type="checkbox" name="docChecked" id="doc_{{document.Id}}" ng-model="document.Filtered" />
        </span>
 <span>{{document.Name}}</span>

</li>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接