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.
}
}
You should probably write all the logic that is there in
$doggedHttp
in a decorator for$http
. Once you decorate$http
, everything should work fineEDIT : Correction for condition.
Alternately, you can write all your storage logic in a
request interceptor
- You can inject anything and everything in there as well, so storing your calls and re-requesting can also be done at that stage.