diff --git a/src/ng/http.js b/src/ng/http.js index 75991b20c57c..84dbd453ab0f 100644 --- a/src/ng/http.js +++ b/src/ng/http.js @@ -694,6 +694,8 @@ function $HttpProvider() { * - **headers** – `{Object}` – Map of strings or functions which return strings representing * HTTP headers to send to the server. If the return value of a function is null, the * header will not be sent. Functions accept a config object as an argument. + * - **events** - `{Object}` - Event listeners to be bound to the XMLHttpRequest object. + * To bind events to the XMLHttpRequest upload object, nest it under the upload key. * - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token. * - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token. * - **transformRequest** – @@ -1155,7 +1157,7 @@ function $HttpProvider() { } $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout, - config.withCredentials, config.responseType); + config.withCredentials, config.responseType, config.events); } return promise; diff --git a/src/ng/httpBackend.js b/src/ng/httpBackend.js index 4eb872cd5f11..7d26ac6efa93 100644 --- a/src/ng/httpBackend.js +++ b/src/ng/httpBackend.js @@ -28,7 +28,7 @@ function $HttpBackendProvider() { function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) { // TODO(vojta): fix the signature - return function(method, url, post, callback, headers, timeout, withCredentials, responseType) { + return function(method, url, post, callback, headers, timeout, withCredentials, responseType, eventHandlers) { $browser.$$incOutstandingRequestCount(); url = url || $browser.url(); @@ -88,6 +88,20 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc xhr.onerror = requestError; xhr.onabort = requestError; + if (eventHandlers) { + forEach(eventHandlers, function(value, key) { + if (key !== 'upload') { + xhr.addEventListener(key, value); + } + }); + + if (eventHandlers.upload) { + forEach(eventHandlers.upload, function(value, key) { + xhr.upload.addEventListener(key, value); + }); + } + } + if (withCredentials) { xhr.withCredentials = true; } diff --git a/src/ngMock/angular-mocks.js b/src/ngMock/angular-mocks.js index dd11e45701ab..0d1973783875 100644 --- a/src/ngMock/angular-mocks.js +++ b/src/ngMock/angular-mocks.js @@ -1683,6 +1683,17 @@ function MockXhr() { }; this.abort = angular.noop; + + this.$$events = {}; + this.addEventListener = function(name, listener) { + if (angular.isUndefined(this.$$events[name])) this.$$events[name] = []; + this.$$events[name].push(listener); + }; + + this.upload = { + $$events: {}, + addEventListener: this.addEventListener + }; } diff --git a/test/ng/httpBackendSpec.js b/test/ng/httpBackendSpec.js index 12ceed5beb01..c57e4118c9d2 100644 --- a/test/ng/httpBackendSpec.js +++ b/test/ng/httpBackendSpec.js @@ -214,6 +214,19 @@ describe('$httpBackend', function() { expect(MockXhr.$$lastInstance.withCredentials).toBe(true); }); + it('should set up event listeners', function() { + var progressFn = function() {}; + var uploadProgressFn = function() {}; + $backend('GET', '/url', null, callback, {}, null, null, null, { + progress: progressFn, + upload: { + progress: uploadProgressFn + } + }); + xhr = MockXhr.$$lastInstance; + expect(xhr.$$events.progress[0]).toBe(progressFn); + expect(xhr.upload.$$events.progress[0]).toBe(uploadProgressFn); + }); describe('responseType', function() {