问题
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