I have a service called $doggedHttp, which exposes the same interface as $http.
Now I want to create a $doggedResource service which is the angular $resource service on top of $doggedHttp instead of $http. In other word I want to inject $doggedHttp as the $http service.
Also, in my application I want to be able to create both $doggedResource and $resource. Thus I cannot simply override $http with $doggedHttp.
I thought dependency injection should make this scenario easy to solve. Am I wrong ?
Instead I had to go deep into the angular source code to finally came up with a quite ugly solution :
angular.module('doggedResource', ['ngResource', 'doggedHttp'])
.config(function() {
var ngResource = angular.module('ngResource'),
doggedResource = angular.module('doggedResource');
// replace the placeholder below with the $resource factory from ngResource
doggedResource._invokeQueue[1][2][1][2] = ngResource._invokeQueue[0][2][1][2];
})
.factory('$doggedResource', ['$doggedHttp', '$parse', null /* this is just a placeholder */]);
Is there a better solution ?
Remark that we cannot use $provide.decorator to replace the injected $http service.
To illustrate the problem, here are the relevant parts of angular-resource.js :
angular.module('ngResource', ['ng']).
factory('$resource', ['$http', '$parse', function($http, $parse) {
function ResourceFactory(url, paramDefaults, actions) {
}
return ResourceFactory;
}
Looking at the code above, the $provide.decorator callback will be passed ResourceFactory as an argument. At that time the dependency $http has already been resolved. And since ResourceFactory use $http inside a closure we cannot change it.
.config(function($provide) {
$provide.decorator( '$resource', [ "$delegate", function( $delegate ) {
// here $delegate is the ResourceFactory which has
// already been linked to `$http` by a closure.
}
}