This repository has been archived by the owner on Apr 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 27.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat($jsonpCallbacks): new service to abstract how JSONP callbacks ar…
…e handled You can now override this service if you have specific requirements about the behaviour and formatting of the JSON_CALLBACK that is sent to the server for `$http.jsonp` requests. Closes #14795
- Loading branch information
1 parent
1a387ba
commit a8cacfe
Showing
4 changed files
with
159 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
'use strict'; | ||
|
||
/** | ||
* @ngdoc service | ||
* @name $jsonpCallbacks | ||
* @requires $window | ||
* @description | ||
* This service handles the lifecycle of callbacks to handle JSONP requests. | ||
* Override this service if you wish to customise where the callbacks are stored and | ||
* how they vary compared to the requested url. | ||
*/ | ||
var $jsonpCallbacksProvider = function() { | ||
this.$get = ['$window', function($window) { | ||
var counter = 0; | ||
$window.angular.callbacks = {}; | ||
var callbackMap = {}; | ||
|
||
function createCallback(callbackId) { | ||
var callback = function(data) { | ||
callback.data = data; | ||
callback.called = true; | ||
}; | ||
callback.id = callbackId; | ||
return callback; | ||
} | ||
|
||
return { | ||
/** | ||
* @ngdoc method | ||
* @name $jsonpCallbacks#createCallback | ||
* @param {string} url the url of the JSONP request | ||
* @returns {string} the callback path to send to the server as part of the JSONP request | ||
* @description | ||
* {@link $httpBackend} calls this method to create a callback and get hold of the path to the callback | ||
* to pass to the server, which will be used to call the callback with its payload in the JSONP response. | ||
*/ | ||
createCallback: function(url) { | ||
var callbackId = '_' + (counter++).toString(36); | ||
var callbackPath = 'angular.callbacks.' + callbackId; | ||
var callback = createCallback(callbackId); | ||
callbackMap[callbackPath] = $window.angular.callbacks[callbackId] = callback; | ||
return callbackPath; | ||
}, | ||
/** | ||
* @ngdoc method | ||
* @name $jsonpCallbacks#wasCalled | ||
* @param {string} callbackPath the path to the callback that was sent in the JSONP request | ||
* @returns {boolean} whether the callback has been called, as a result of the JSONP response | ||
* @description | ||
* {@link $httpBackend} calls this method to find out whether the JSONP response actually called the | ||
* callback that was passed in the request. | ||
*/ | ||
wasCalled: function(callbackPath) { | ||
return callbackMap[callbackPath].called; | ||
}, | ||
/** | ||
* @ngdoc method | ||
* @name $jsonpCallbacks#getResponse | ||
* @param {string} callbackPath the path to the callback that was sent in the JSONP request | ||
* @returns {*} the data received from the response via the registered callback | ||
* @description | ||
* {@link $httpBackend} calls this method to get hold of the data that was provided to the callback | ||
* in the JSONP response. | ||
*/ | ||
getResponse: function(callbackPath) { | ||
return callbackMap[callbackPath].data; | ||
}, | ||
/** | ||
* @ngdoc method | ||
* @name $jsonpCallbacks#removeCallback | ||
* @param {string} callbackPath the path to the callback that was sent in the JSONP request | ||
* @description | ||
* {@link $httpBackend} calls this method to remove the callback after the JSONP request has | ||
* completed or timed-out. | ||
*/ | ||
removeCallback: function(callbackPath) { | ||
var callback = callbackMap[callbackPath]; | ||
delete $window.angular.callbacks[callback.id]; | ||
delete callbackMap[callbackPath]; | ||
} | ||
}; | ||
}]; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
'use strict'; | ||
|
||
describe('$jsonpCallbacks', function() { | ||
|
||
beforeEach(module(function($provide) { | ||
// mock out the $window object | ||
$provide.value('$window', { angular: {} }); | ||
})); | ||
|
||
describe('createCallback(url)', function() { | ||
|
||
it('should return a new unique path to a callback function on each call', inject(function($jsonpCallbacks) { | ||
var path = $jsonpCallbacks.createCallback('http://some.dummy.com/jsonp/request'); | ||
expect(path).toEqual('angular.callbacks._0'); | ||
|
||
path = $jsonpCallbacks.createCallback('http://some.dummy.com/jsonp/request'); | ||
expect(path).toEqual('angular.callbacks._1'); | ||
|
||
path = $jsonpCallbacks.createCallback('http://some.dummy.com/jsonp/request'); | ||
expect(path).toEqual('angular.callbacks._2'); | ||
|
||
path = $jsonpCallbacks.createCallback('http://some.dummy.com/jsonp/request'); | ||
expect(path).toEqual('angular.callbacks._3'); | ||
})); | ||
|
||
it('should add a callback method to the $window.angular.callbacks collection on each call', inject(function($window, $jsonpCallbacks) { | ||
$jsonpCallbacks.createCallback('http://some.dummy.com/jsonp/request'); | ||
expect($window.angular.callbacks._0).toEqual(jasmine.any(Function)); | ||
|
||
$jsonpCallbacks.createCallback('http://some.dummy.com/jsonp/request'); | ||
expect($window.angular.callbacks._1).toEqual(jasmine.any(Function)); | ||
|
||
$jsonpCallbacks.createCallback('http://some.dummy.com/jsonp/request'); | ||
expect($window.angular.callbacks._2).toEqual(jasmine.any(Function)); | ||
|
||
$jsonpCallbacks.createCallback('http://some.dummy.com/jsonp/request'); | ||
expect($window.angular.callbacks._3).toEqual(jasmine.any(Function)); | ||
})); | ||
}); | ||
|
||
|
||
describe('wasCalled(callbackPath)', function() { | ||
|
||
it('should return true once the callback has been called', inject(function($window, $jsonpCallbacks) { | ||
var path = $jsonpCallbacks.createCallback('http://some.dummy.com/jsonp/request'); | ||
expect($jsonpCallbacks.wasCalled(path)).toBeFalsy(); | ||
var response = {}; | ||
$window.angular.callbacks._0(response); | ||
expect($jsonpCallbacks.wasCalled(path)).toBeTruthy(); | ||
})); | ||
}); | ||
|
||
|
||
describe('getResponse(callbackPath)', function() { | ||
|
||
it('should retrieve the data from when the callback was called', inject(function($window, $jsonpCallbacks) { | ||
var path = $jsonpCallbacks.createCallback('http://some.dummy.com/jsonp/request'); | ||
var response = {}; | ||
$window.angular.callbacks._0(response); | ||
var result = $jsonpCallbacks.getResponse(path); | ||
expect(result).toBe(response); | ||
})); | ||
}); | ||
|
||
describe('removeCallback(calbackPath)', function() { | ||
|
||
it('should remove the callback', inject(function($window, $jsonpCallbacks) { | ||
var path = $jsonpCallbacks.createCallback('http://some.dummy.com/jsonp/request'); | ||
$jsonpCallbacks.removeCallback(path); | ||
expect($window.angular.callbacks._0).toBeUndefined(); | ||
})); | ||
}); | ||
}); |