Skip to content

Commit d497822

Browse files
feat($http): support handling additional XHR events
Closes angular#14367 Closes angular#11547 Closes angular#1934
1 parent 50cdede commit d497822

File tree

5 files changed

+73
-24
lines changed

5 files changed

+73
-24
lines changed

src/ng/http.js

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -801,8 +801,12 @@ function $HttpProvider() {
801801
* - **headers** – `{Object}` – Map of strings or functions which return strings representing
802802
* HTTP headers to send to the server. If the return value of a function is null, the
803803
* header will not be sent. Functions accept a config object as an argument.
804-
* - **events** - `{Object}` - Event listeners to be bound to the XMLHttpRequest object.
805-
* To bind events to the XMLHttpRequest upload object, nest it under the upload key.
804+
* - **eventHandlers** - `{Object}` - Event listeners to be bound to the XMLHttpRequest object.
805+
* To bind events to the XMLHttpRequest upload object, use `uploadEventHandlers`.
806+
* The handler will be called in the context of a `$apply` block.
807+
* - **uploadEventHandlers** - `{Object}` - Event listeners to be bound to the XMLHttpRequest upload
808+
* object. To bind events to the XMLHttpRequest object, use `eventHandlers`.
809+
* The handler will be called in the context of a `$apply` block.
806810
* - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
807811
* - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
808812
* - **transformRequest** –
@@ -1261,11 +1265,31 @@ function $HttpProvider() {
12611265
}
12621266

12631267
$httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
1264-
config.withCredentials, config.responseType, config.events);
1268+
config.withCredentials, config.responseType,
1269+
createApplyHandlers(config.eventHandlers),
1270+
createApplyHandlers(config.uploadEventHandlers));
12651271
}
12661272

12671273
return promise;
12681274

1275+
function createApplyHandlers(eventHandlers) {
1276+
if (eventHandlers) {
1277+
var applyHandlers = {};
1278+
forEach(eventHandlers, function(eventHandler, key) {
1279+
applyHandlers[key] = function() {
1280+
if (useApplyAsync) {
1281+
$rootScope.$applyAsync(eventHandler);
1282+
} else if ($rootScope.$$phase) {
1283+
eventHandler();
1284+
} else {
1285+
$rootScope.$apply(eventHandler);
1286+
}
1287+
};
1288+
});
1289+
return applyHandlers;
1290+
}
1291+
}
1292+
12691293

12701294
/**
12711295
* Callback registered to $httpBackend():

src/ng/httpBackend.js

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ function $HttpBackendProvider() {
5454

5555
function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
5656
// TODO(vojta): fix the signature
57-
return function(method, url, post, callback, headers, timeout, withCredentials, responseType, eventHandlers) {
57+
return function(method, url, post, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers) {
5858
$browser.$$incOutstandingRequestCount();
5959
url = url || $browser.url();
6060

@@ -114,19 +114,13 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
114114
xhr.onerror = requestError;
115115
xhr.onabort = requestError;
116116

117-
if (eventHandlers) {
118-
forEach(eventHandlers, function(value, key) {
119-
if (key !== 'upload') {
120-
xhr.addEventListener(key, value);
121-
}
122-
});
117+
forEach(eventHandlers, function(value, key) {
118+
xhr.addEventListener(key, value);
119+
});
123120

124-
if (eventHandlers.upload) {
125-
forEach(eventHandlers.upload, function(value, key) {
126-
xhr.upload.addEventListener(key, value);
127-
});
128-
}
129-
}
121+
forEach(uploadEventHandlers, function(value, key) {
122+
xhr.upload.addEventListener(key, value);
123+
});
130124

131125
if (withCredentials) {
132126
xhr.withCredentials = true;

src/ngMock/angular-mocks.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1322,12 +1322,15 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
13221322
}
13231323

13241324
// TODO(vojta): change params to: method, url, data, headers, callback
1325-
function $httpBackend(method, url, data, callback, headers, timeout, withCredentials, responseType) {
1325+
function $httpBackend(method, url, data, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers) {
13261326

13271327
var xhr = new MockXhr(),
13281328
expectation = expectations[0],
13291329
wasExpected = false;
13301330

1331+
xhr.$$events = eventHandlers;
1332+
xhr.upload.$$events = uploadEventHandlers;
1333+
13311334
function prettyPrint(data) {
13321335
return (angular.isString(data) || angular.isFunction(data) || data instanceof RegExp)
13331336
? data
@@ -2011,6 +2014,9 @@ function MockXhr() {
20112014

20122015
this.abort = angular.noop;
20132016

2017+
// This section simulates the events on a real XHR object (and the upload object)
2018+
// When we are testing $httpBackend (inside the angular project) we make partial use of this
2019+
// but store the events directly ourselves on `$$events`, instead of going through the `addEventListener`
20142020
this.$$events = {};
20152021
this.addEventListener = function(name, listener) {
20162022
if (angular.isUndefined(this.$$events[name])) this.$$events[name] = [];

test/ng/httpBackendSpec.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -244,12 +244,8 @@ describe('$httpBackend', function() {
244244
it('should set up event listeners', function() {
245245
var progressFn = function() {};
246246
var uploadProgressFn = function() {};
247-
$backend('GET', '/url', null, callback, {}, null, null, null, {
248-
progress: progressFn,
249-
upload: {
250-
progress: uploadProgressFn
251-
}
252-
});
247+
$backend('GET', '/url', null, callback, {}, null, null, null,
248+
{progress: progressFn}, {progress: uploadProgressFn});
253249
xhr = MockXhr.$$lastInstance;
254250
expect(xhr.$$events.progress[0]).toBe(progressFn);
255251
expect(xhr.upload.$$events.progress[0]).toBe(uploadProgressFn);

test/ng/httpSpec.js

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
'use strict';
22

3+
/* global MockXhr: false */
4+
35
describe('$http', function() {
46

57
var callback, mockedCookies;
@@ -1019,7 +1021,7 @@ describe('$http', function() {
10191021
});
10201022

10211023

1022-
describe('scope.$apply', function() {
1024+
describe('callbacks', function() {
10231025

10241026
it('should $apply after success callback', function() {
10251027
$httpBackend.when('GET').respond(200);
@@ -1047,6 +1049,33 @@ describe('$http', function() {
10471049

10481050
$exceptionHandler.errors = [];
10491051
}));
1052+
1053+
1054+
it('should pass the event handlers through to the backend', function() {
1055+
var progressFn = jasmine.createSpy('progressFn');
1056+
var uploadProgressFn = jasmine.createSpy('uploadProgressFn');
1057+
$httpBackend.when('GET').respond(200);
1058+
$http({
1059+
method: 'GET',
1060+
url: '/some',
1061+
eventHandlers: {progress: progressFn},
1062+
uploadEventHandlers: {progress: uploadProgressFn}
1063+
});
1064+
$rootScope.$apply();
1065+
var mockXHR = MockXhr.$$lastInstance;
1066+
expect(mockXHR.$$events.progress).toEqual(jasmine.any(Function));
1067+
expect(mockXHR.upload.$$events.progress).toEqual(jasmine.any(Function));
1068+
1069+
spyOn($rootScope, '$digest');
1070+
1071+
mockXHR.$$events.progress();
1072+
expect(progressFn).toHaveBeenCalledOnce();
1073+
expect($rootScope.$digest).toHaveBeenCalledTimes(1);
1074+
1075+
mockXHR.upload.$$events.progress();
1076+
expect(uploadProgressFn).toHaveBeenCalledOnce();
1077+
expect($rootScope.$digest).toHaveBeenCalledTimes(2);
1078+
});
10501079
});
10511080

10521081

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy