Sharing Top Content from the Angular-sphere.

[SOLVED] I need two instances of AngularJS $http service or what?- Angular.js Recipes

  • I want add a response interceptor to my $http service for error handling purposes.
  • My idea was create a service named ‘remote_log’ and put inside it all the code needed to send error to server.
  • Then add as dependency of the interceptor to the ‘remote_log’ service, and use the ‘remote_log’ inside the interceptor when need send errors to the server.
  • The problems is that:

    Interceptors must be defined using the $httpProvider when the $http service still is not instantiated/accessible, so, inside the interceptor code can’t be a dependency to that the $http service because a “Circular dependency” error happen.

  • I think my only option is create a separate instance of the $http service inside my ‘remote_log’, an instance that don’t uses the $httpProvider configuration I set while creating the interceptor.

1. Circular dependency problem.

So, why does the error appear? Here is a quick overview of the process:

$http service is requested.
$httpProvider is asked to construct it.
During construction you register interceptor, that requests $http service not existing yet.
You get “Circular dependency” error.

First solution.

Create your dependency using angular.injector(). Notice, that you will create another $http service, independent from your app.

$httpProvider.interceptors.push(function($q) {
$injector = angular.injector();
return {
response: function(response) {
$injector.invoke(function($http) {
// This is the exterior $http service!
// This interceptor will not affect it.
});
}
};
});

Second solution (better).

Inject $injector in your interceptor and use it to retrieve dependencies after $http initialization, right at the time you need them. These dependencies are registered services of your app and will not be created anew!

$httpProvider.interceptors.push(function($q, $injector) {
return {
response: function(response) {
$injector.invoke(function($http, someService) {
// $http is already constructed at the time and you may
// use it, just as any other service registered in your
// app module and modules on which app depends on.
});
}
};
});

2. Interception prevention problem.

If you use the second solution, there are actually two problems:

If you utilize $http service inside your
interceptor, you may end up with infinite interceptions: you send
request, interceptor catches it, sends another, catches another,
send again, and so on.
Sometimes you want just prevent request from being intercepted.

The ‘config’ parameter of $http service is just an object. You may create a convention, providing custom parameters and recognizing them in your interceptors.

For example, let’s add “nointercept” property to config and try duplicate every user request. This is a silly application, but useful example to understand the behavior:

$httpProvider.interceptors.push(function($q, $injector) {
return {
response: function(response) {
if (response.config.nointercept) {
return $q.when(response); // let it pass
} else {
var defer = $q.defer();
$injector.invoke(function($http) {
// This modification prevents interception:
response.config.nointercept = true;
// Reuse modified config and send the same request again:
$http(response.config)
.then(function(resp) { defer.resolve(resp); },
function(resp) { defer.reject(resp); });
});
return defer.promise;
}
}
};
});

Having the testing for property in interceptor, you may prevent the interception in controllers and services:

app.controller(‘myController’, function($http) {
// The second parameter is actually ‘config’, see API docs.
// This query will not be duplicated by the interceptor.
$http.get(‘/foo/bar’, {nointercept: true})
.success(function(data) {
// …
});

});


@angular_recipe: I need two instances of AngularJS $http service or what? #Angular #AngularJS

I want add a response interceptor to my $http service for error handling purposes. The interceptor logic include send errors messages to server using $http in case necessary, BUT I don’t want send errors messages to the server about errors messages, I mean, I want disable my interceptor while sending error message to the server.

My idea was create a service named ‘remote_log’ and put inside it all the code needed to send error to server. That service of course will use the $http service and have it in its dependency list.

Then add as dependency of the interceptor to the ‘remote_log’ service, and use the ‘remote_log’ inside the interceptor when need send errors to the server. The problems is that:

Interceptors must be defined using the $httpProvider when the $http service still is not instantiated/accessible, so, inside the interceptor code can’t be a dependency to that the $http service because a “Circular dependency” error happen.

I think my only option is create a separate instance of the $http service inside my ‘remote_log’, an instance that don’t uses the $httpProvider configuration I set while creating the interceptor. My question is: How can I do that? Any other ideas?

So, why does the error appear? Here is a quick overview of the process:

$http service is requested.

$httpProvider is asked to construct it.

During construction you register interceptor, that requests $http service not existing yet.

You get “Circular dependency” error.

Create your dependency using angular.injector(). Notice, that you will create another $http service, independent from your app.

$httpProvider.interceptors.push(function($q) { $injector = angular.injector(); return { response: function(response) { $injector.invoke(function($http) { // This is the exterior $http service! // This interceptor will not affect it. }); } }; });

Inject $injector in your interceptor and use it to retrieve dependencies after $http initialization, right at the time you need them. These dependencies are registered services of your app and will not be created anew!

$httpProvider.interceptors.push(function($q, $injector) { return { response: function(response) { $injector.invoke(function($http, someService) { // $http is already constructed at the time and you may // use it, just as any other service registered in your // app module and modules on which app depends on. }); } }; });

If you use the second solution, there are actually two problems:

If you utilize $http service inside your interceptor, you may end up with infinite interceptions: you send request, interceptor catches it, sends another, catches another, send again, and so on.

Sometimes you want just prevent request from being intercepted.

The ‘config’ parameter of $http service is just an object. You may create a convention, providing custom parameters and recognizing them in your interceptors.

For example, let’s add “nointercept” property to config and try duplicate every user request. This is a silly application, but useful example to understand the behavior:

$httpProvider.interceptors.push(function($q, $injector) { return { response: function(response) { if (response.config.nointercept) { return $q.when(response); // let it pass } else { var defer = $q.defer(); $injector.invoke(function($http) { // This modification prevents interception: response.config.nointercept = true; // Reuse modified config and send the same request again: $http(response.config) .then(function(resp) { defer.resolve(resp); }, function(resp) { defer.reject(resp); }); }); return defer.promise; } } }; });

Having the testing for property in interceptor, you may prevent the interception in controllers and services:

app.controller(‘myController’, function($http) { // The second parameter is actually ‘config’, see API docs. // This query will not be duplicated by the interceptor. $http.get(‘/foo/bar’, {nointercept: true}) .success(function(data) { // … }); });

I used what is described in the answer but I used the syntax with a factory because with the anonymous function it didn’t work, I don’t really know why:

Angular.js Recipes are structured in a Cookbook format featuring recipes that contain problem statements and solutions. A detailed explanation follows each problem statement of the recipe. This is usually contained within the solution; however, an optional discussion section can often contain other useful information helping to demonstrate how the solution works.

Angular.js is a JavaScript-based open-source front-end web application framework mainly maintained by Google and by a community of individuals and corporations to address many of the challenges encountered in developing single-page applications. The JavaScript components complement Apache Cordova, the framework used for developing cross-platform mobile apps. It aims to simplify both the development and the testing of such applications by providing a framework for client-side model–view–controller (MVC) and model–view–viewmodel (MVVM) architectures, along with components commonly used in rich Internet applications.

Lost? Begin by working through Angular’s Getting Started Guide to get yourself up-and-running.

[SOLVED] I need two instances of AngularJS $http service or what?- Angular.js Recipes

Comments are closed, but trackbacks and pingbacks are open.