Angular:$ resource更新仅在第二次调用时触发PUT请求

时间:2013-06-21 14:59:33

标签: angularjs angularjs-directive angularjs-scope

我有一个带有自定义更新方法的资源:

angular.module('user.resources', ['ngResource']).
factory('User', function($resource) {
  var User = $resource('/user/:id', {}, {
    update: {
      method: 'PUT'
    }
  });

  User.prototype.update = function(cb) {
    console.log('foo');
    return User.update({
      id: this._id
    }, angular.extend({}, this, {
      _id: undefined
    }), cb);
  };

我正在通过范围将此资源传递给自定义指令:

directive('avatarUpload', function($http) {
  return {
    restrict: 'E',
    scope: {
      model: '='
    }, ...

我在btn点击中调用指令控制器中的update方法:

$scope.model.update(function() {
  console.log('bar');
});

让我困惑的行为是第一次点击按钮'foo'而不是'bar',点击第二次打印'bar',然后'foo'。再点击总是打印'bar'然后'foo'。

PUT请求仅从第二次点击和之后的点击,而不是从第一次点击。

注意:我一直在控制器中使用该资源更新方法,直到尝试从指令调用它。我正在使用角1.1.4 我执行此资源传递是因为我希望该指令适用于不同类型的资源。

1 个答案:

答案 0 :(得分:7)

在没有看到实时代码示例的情况下很难肯定,但我认为您正在使用1.1.x系列中的AngularJS(所谓的“不稳定分支”)。如果是这样,您遇到的问题与AngularJS中的新功能相关联 - 版本1.1.4中引入的HTTP请求拦截器(此commit)。

新引入的请求拦截器基于$q(基于承诺),在AngularJS中,世界承诺仅作为$digest周期的一部分进行解析。换句话说,您需要处于“AngularJS世界”($digest周期)中才能解决承诺。

使用基于承诺的请求拦截器,可以在进行$http呼叫之前解决。如前所述,此承诺只能在您输入$digest周期时解决。如果从AngularJS(DOM事件,setTimeout等)之外启动$http,则不会发生这种情况。

在AngularJS中,$resource基于$http,因此上述讨论也适用于$resource

所以,假设上述假设是正确的,并且你正在从AngularJS之外发起$resource调用(你正在谈论一个自定义指令,所以我会赌一个DOM事件)你应该只是将$resource电话打包到scope.$apply

请注意,将$resource电话打包到$timeout(如另一个回复中所示),同时将“修复”您的问题(它将强制执行$ digest循环,因此承诺将得到解决) 这不是正确的方法。问题是它会强制浏览器离开当前的JavaScript上下文并输入重绘上下文。它会使您的应用程序变慢,并可能导致UI闪烁。