Angular: $resource update fire PUT request on second call only

筅森魡賤 提交于 2019-12-08 08:03:51

问题


I have a resource with a custom update method :

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);
  };

I'm passing this resource to a custom directive via scope:

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

and I'm calling the update method in the directive controller on a btn click:

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

The behavior which puzzle me atm is that clicking on the button the first time print 'foo' but not 'bar', clicking it a second time print 'bar', then 'foo'. Any more click always print 'bar' then 'foo'.

The PUT request is only fired from the second click and the ones after, never from the first.

Note: I've been using that resource update method fine in controllers, until trying to call it from a directive. I'm using angular 1.1.4 I do this resource passing because I want the directive to work on different type of resource.


回答1:


It is hard to say for sure without seeing live code example but I presume that you are using AngularJS from the 1.1.x series (so called "unstable branch"). If so, the problem you are facing is linked to the new feature in AngularJS - HTTP request interceptors introduced in version 1.1.4 (this commit).

The newly introduced request interceptors are $q-based (promise-based) and in AngularJS world promises are only resolved as part of the $digest cycle. In other words you need to be in the "AngularJS world" ($digest cycle) for the promises to be resolved.

With the promise-based request interceptors there is a promise to be resolved before a $http call can be made. As as noted before this promise can only be resolved when you enter the $digest cycle. This won't happen if you are initiating the $http from outside of AngularJS (DOM event, setTimeout etc.).

In AngularJS $resource is based on $http so the above discussion apply to the $resource as well.

So, presuming that the above assumptions are correct and you are initiating the $resource call from outside of AngularJS (you are talking about a custom directive so I would bet on a DOM event) you should simply wrap the $resource call into scope.$apply.

Please note that wrapping the $resource call into $timeout (as suggested in another response), while will "fix" your issue (it will force a $digest loop and thus promises will get resolved) it is not the correct approach. The problem is that it will force a browser to leave the current JavaScript context and enter the repaint context for nothing. It will make your application slower and may result in UI flickering.



来源:https://stackoverflow.com/questions/17238411/angular-resource-update-fire-put-request-on-second-call-only

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!