Angular: restarting $ resource fire PUT request for second call

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 pass this resource to the user directive by area:

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

and I call the update method in the directive controller on the btn click:

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

The behavior that makes me puzzle is that clicking the button for the first time prints β€œfoo” but not β€œbar”, clicking on it a second time β€œbar” and then β€œfoo”. Any click always prints "bar" and then "foo".

The PUT request is launched only from the second click, and after - never, starting from the first.

Note. I use this method of updating resources in controllers until I try to call it from a directive. I am using angular 1.1.4 I am passing this resource because I want the directive to work with different types of resources.

+1
source share
1 answer

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

Recently introduced request interceptors are based on $q (based on promises), and in the world of AngularJS promises are only allowed as part of the $digest loop. In other words, you need to be in the "AngularJS world" ( $digest ) loop for promises, which should be allowed.

With promise-based request interceptors, there is a promise to be resolved before calling $http . As noted earlier, this promise can only be resolved by entering the $digest loop. This will not happen if you initiate $http from outside AngularJS (DOM event, setTimeout, etc.).

In AngularJS, $resource based on $http , so the discussion above applies to $resource .

So, assuming that the above assumptions are correct, and you initiate a call to $resource from outside AngularJS (you are talking about a user directive, so I bet on the DOM event) , you just have to wrap $resource a scope.$apply call .

Note that wrapping the call to $resource in $timeout (as suggested in another answer), while it will β€œfix” your problem (it will cause the $ digest loop and therefore promises to be solved), this is not the right approach. The problem is that it will force the browser to leave the current JavaScript context and enter the redraw context for nothing. This will make your application slower and may cause the user interface to flash.

+7
source

Source: https://habr.com/ru/post/948813/


All Articles