Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Added invokeApply parameter to $http to skip apply #12557

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 24 additions & 10 deletions src/ng/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,8 @@ function $HttpProvider() {
* - **responseType** - `{string}` - see
* [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype).
*
* @param {boolean=} invokeApply: if false, skips model dirty checking after request succeeds
*
* @returns {HttpPromise} Returns a {@link ng.$q `Promise}` that will be resolved to a response object
* when the request succeeds or fails.
*
Expand Down Expand Up @@ -920,7 +922,7 @@ function $HttpProvider() {
</file>
</example>
*/
function $http(requestConfig) {
function $http(requestConfig, invokeApply) {

if (!angular.isObject(requestConfig)) {
throw minErr('$http')('badreq', 'Http request configuration must be an object. Received: {0}', requestConfig);
Expand Down Expand Up @@ -956,7 +958,7 @@ function $HttpProvider() {
}

// send request
return sendReq(config, reqData).then(transformResponse, transformResponse);
return sendReq(config, reqData, invokeApply).then(transformResponse, transformResponse);
};

var chain = [serverRequest, undefined];
Expand Down Expand Up @@ -1083,6 +1085,7 @@ function $HttpProvider() {
*
* @param {string} url Relative or absolute URL specifying the destination of the request
* @param {Object=} config Optional configuration object
* @param {boolean=} invokeApply: if false, skips model dirty checking after request succeeds
* @returns {HttpPromise} Future object
*/

Expand All @@ -1095,6 +1098,7 @@ function $HttpProvider() {
*
* @param {string} url Relative or absolute URL specifying the destination of the request
* @param {Object=} config Optional configuration object
* @param {boolean=} invokeApply: if false, skips model dirty checking after request succeeds
* @returns {HttpPromise} Future object
*/

Expand All @@ -1108,6 +1112,7 @@ function $HttpProvider() {
* @param {string} url Relative or absolute URL specifying the destination of the request.
* The name of the callback should be the string `JSON_CALLBACK`.
* @param {Object=} config Optional configuration object
* @param {boolean=} invokeApply: if false, skips model dirty checking after request succeeds
* @returns {HttpPromise} Future object
*/
createShortMethods('get', 'delete', 'head', 'jsonp');
Expand All @@ -1122,6 +1127,7 @@ function $HttpProvider() {
* @param {string} url Relative or absolute URL specifying the destination of the request
* @param {*} data Request content
* @param {Object=} config Optional configuration object
* @param {boolean=} invokeApply: if false, skips model dirty checking after request succeeds
* @returns {HttpPromise} Future object
*/

Expand All @@ -1135,6 +1141,7 @@ function $HttpProvider() {
* @param {string} url Relative or absolute URL specifying the destination of the request
* @param {*} data Request content
* @param {Object=} config Optional configuration object
* @param {boolean=} invokeApply: if false, skips model dirty checking after request succeeds
* @returns {HttpPromise} Future object
*/

Expand All @@ -1148,6 +1155,7 @@ function $HttpProvider() {
* @param {string} url Relative or absolute URL specifying the destination of the request
* @param {*} data Request content
* @param {Object=} config Optional configuration object
* @param {boolean=} invokeApply: if false, skips model dirty checking after request succeeds
* @returns {HttpPromise} Future object
*/
createShortMethodsWithData('post', 'put', 'patch');
Expand All @@ -1170,24 +1178,24 @@ function $HttpProvider() {

function createShortMethods(names) {
forEach(arguments, function(name) {
$http[name] = function(url, config) {
$http[name] = function(url, config, invokeApply) {
return $http(extend({}, config || {}, {
method: name,
url: url
}));
}), invokeApply);
};
});
}


function createShortMethodsWithData(name) {
forEach(arguments, function(name) {
$http[name] = function(url, data, config) {
$http[name] = function(url, data, config, invokeApply) {
return $http(extend({}, config || {}, {
method: name,
url: url,
data: data
}));
}), invokeApply);
};
});
}
Expand All @@ -1199,7 +1207,7 @@ function $HttpProvider() {
* !!! ACCESSES CLOSURE VARS:
* $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
*/
function sendReq(config, reqData) {
function sendReq(config, reqData, invokeApply) {
var deferred = $q.defer(),
promise = deferred.promise,
cache,
Expand Down Expand Up @@ -1276,11 +1284,17 @@ function $HttpProvider() {
resolvePromise(response, status, headersString, statusText);
}

if (useApplyAsync) {
$rootScope.$applyAsync(resolveHttpPromise);
var skipApply = (isDefined(invokeApply) && !invokeApply);

if (!skipApply) {
if (useApplyAsync) {
$rootScope.$applyAsync(resolveHttpPromise);
} else {
resolveHttpPromise();
if (!$rootScope.$$phase) $rootScope.$apply();
}
} else {
resolveHttpPromise();
if (!$rootScope.$$phase) $rootScope.$apply();
}
}

Expand Down
82 changes: 63 additions & 19 deletions test/ng/httpSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1013,32 +1013,76 @@ describe('$http', function() {

describe('scope.$apply', function() {

it('should $apply after success callback', function() {
$httpBackend.when('GET').respond(200);
$http({method: 'GET', url: '/some'});
$httpBackend.flush();
expect($rootScope.$apply).toHaveBeenCalledOnce();
});
describe('when invokeApply is undefined', function() {

it('should $apply after success callback', function() {
$httpBackend.when('GET').respond(200);
$http({method: 'GET', url: '/some'});
$httpBackend.flush();
expect($rootScope.$apply).toHaveBeenCalledOnce();
});

it('should $apply after error callback', function() {
$httpBackend.when('GET').respond(404);
$http({method: 'GET', url: '/some'});
$httpBackend.flush();
expect($rootScope.$apply).toHaveBeenCalledOnce();

it('should $apply after error callback', function() {
$httpBackend.when('GET').respond(404);
$http({method: 'GET', url: '/some'});
$httpBackend.flush();
expect($rootScope.$apply).toHaveBeenCalledOnce();
});


it('should $apply even if exception thrown during callback', inject(function($exceptionHandler) {
$httpBackend.when('GET').respond(200);
callback.andThrow('error in callback');

$http({method: 'GET', url: '/some'}).then(callback);
$httpBackend.flush();
expect($rootScope.$apply).toHaveBeenCalledOnce();

$exceptionHandler.errors = [];
}));
});

describe('when invokeApply is defined and falsy', function() {

it('should $apply even if exception thrown during callback', inject(function($exceptionHandler) {
$httpBackend.when('GET').respond(200);
callback.andThrow('error in callback');
it('should resolve promises anyway', function() {
$httpBackend.when('GET').respond(200);
var promiseCompleted = false;
$http({method: 'GET', url: '/some'}, false).then(function() {
promiseCompleted = true;
});
$httpBackend.flush();
expect(promiseCompleted).toBe(true);
});

$http({method: 'GET', url: '/some'}).then(callback);
$httpBackend.flush();
expect($rootScope.$apply).toHaveBeenCalledOnce();

$exceptionHandler.errors = [];
}));
it('should not $apply after success callback', function() {
$httpBackend.when('GET').respond(200);
$http({method: 'GET', url: '/some'}, false);
$httpBackend.flush();
expect($rootScope.$apply).not.toHaveBeenCalledOnce();
});


it('should not $apply after error callback', function() {
$httpBackend.when('GET').respond(404);
$http({method: 'GET', url: '/some'}, false);
$httpBackend.flush();
expect($rootScope.$apply).not.toHaveBeenCalledOnce();
});


it('should not $apply if exception thrown during callback', inject(function($exceptionHandler) {
$httpBackend.when('GET').respond(200);
callback.andThrow('error in callback');

$http({method: 'GET', url: '/some'}, false).then(callback);
$httpBackend.flush();
expect($rootScope.$apply).not.toHaveBeenCalledOnce();

$exceptionHandler.errors = [];
}));
});
});


Expand Down