问题描述
我有一个带有自定义更新方法的资源:
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: '='
}, ...
我在 btn 单击时调用指令控制器中的更新方法:
and I'm calling the update method in the directive controller on a btn click:
$scope.model.update(function() {
console.log('bar');
});
令我困惑的行为是第一次点击按钮打印foo"而不是bar",第二次点击它打印bar",然后是foo".再点击总是打印bar"然后打印foo".
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'.
PUT 请求仅从第二次点击和之后的点击触发,而不会从第一次触发.
The PUT request is only fired from the second click and the ones after, never from the first.
注意:我一直在控制器中很好地使用资源更新方法,直到尝试从指令中调用它.我正在使用角 1.1.4我执行此资源传递是因为我希望该指令适用于不同类型的资源.
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.4I do this resource passing because I want the directive to work on different type of resource.
推荐答案
如果没有看到实时代码示例,很难确定,但我认为您正在使用 1.1.x 系列中的 AngularJS(所谓的不稳定分支")).如果是这样,您面临的问题与 AngularJS 中的新功能有关 - 1.1.4 版中引入的 HTTP 请求拦截器(这个 提交).
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).
新引入的请求拦截器是基于 $q
(基于承诺)的,在 AngularJS 世界中,承诺仅作为 $digest
循环的一部分被解析.换句话说,您需要在AngularJS 世界"($digest
循环)中才能解决承诺.
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.
使用基于承诺的请求拦截器,可以在进行 $http
调用之前解决承诺.如前所述,这个承诺只有在您进入 $digest
循环时才能解决.如果您从 AngularJS 外部(DOM 事件、setTimeout 等)启动 $http
,则不会发生这种情况.
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.).
在 AngularJS 中,$resource
基于 $http
,所以上面的讨论也适用于 $resource
.
In AngularJS $resource
is based on $http
so the above discussion apply to the $resource
as well.
因此,假设上述假设是正确的,并且您正在从 AngularJS 外部启动 $resource
调用(您正在谈论自定义指令,所以我打赌 DOM 事件)您应该简单地将 $resource
调用包装到 scope.$apply
中.
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
.
请注意,将 $resource
调用包装到 $timeout
(如另一个回复中所建议的),同时将修复"您的问题(它会强制 $digest循环,因此承诺将得到解决)这不是正确的方法.问题是它会强制浏览器离开当前的 JavaScript 上下文并白白进入重绘上下文.它会使您的应用程序变慢,并可能导致 UI 闪烁.
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.
这篇关于Angular:$resource update 仅在第二次调用时触发 PUT 请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!