This question already has answers here:
AngularJS Error: $injector:modulerr after being minified
(3 answers)
Closed 3 years ago.
I have the following .config code:
angular.module('app').config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push(JSONInterceptor);
}]);
JSONInterceptor is just a simple function:
function JSONInterceptor($q, localStorageService) {
const API_URL = 'http://localhost:3000';
return {
request: function (config) {
const url = config.url;
// ignore template requests
if (url.includes('.html')) {
return config || $q.when(config);
}
if (localStorageService.get('use-json-server')) {
config.url = API_URL + config.url;
}
return config || $q.when(config);
}
};
}
The issue I am experiencing is that when I run the app in its non-minified form, everything works as expected. However, when I minify the app, I get an error for a seemingly unrelated service (though I guess they are related in the sense that they both touch $http):
Error: $injector:unpr
Unknown Provider
Unknown provider: eProvider <- e <- $http <- $uiRouter
I assume that this error has something to do with using a non-angular function as the interceptor (i.e., it is not a .provider or a .factory etc.), but I am not sure, and my attempts to make JSONInterceptor a provider have failed thus far. I know that .config has restrictions as to what can be included. However, even if this is the issue, I am having trouble understanding why it works unminified - I would assume that the same restrictions would apply to minified and unminified code.
Most likely the issue happens because of the dependencies injected in the interceptor ($q, localStorageService) as they are missing annotations.
To resolve this issue, try to register the interceptor as a factory as follows:
angular.module('app').config(['$httpProvider', '$provide', function($httpProvider, $provide) {
$provide.factory('JSONInterceptor', ['$q', 'localStorageService', function ($q, localStorageService) {
const API_URL = 'http://localhost:3000';
return {
request: function (config) {
const url = config.url;
// ignore template requests
if (url.includes('.html')) {
return config || $q.when(config);
}
if (localStorageService.get('use-json-server')) {
config.url = API_URL + config.url;
}
return config || $q.when(config);
}
};
}]);
$httpProvider.interceptors.push('JSONInterceptor');
}]);
Related
I'm writing an ionic v1/express/mongo/node app. When checking if the user is authenticated i have the following piece of code:
checkAuthentication: function(token) {
console.log(token);
return $http.get("http://validUrl/test", {
headers: {
'testingAuth': token
}
}).then(function(result) {
return result.data;
});
}
and am calling it like this:
checkAuthentication(token).then(function(response) {
console.log("testing response: " + response);
// if a valid token is already in storage = response contains "Success"(?), just $state.go to main page, else call the login() function
if (response.content === "Success") {
// $state.go main page
} else {
console.log("could not log in");
}
})
The problem is, when I get back code 401 from the server, I somehow skip the then block in the checkAuthentication function. Execution doesn't stop at a breakpoint at "return result.data", or "console.log("could not log").
Am I doing something obviously wrong? Is there something i need to do to force going into that block? Thanks for any advice.
The issue is with your error handling ! I took the liberty to modify your code and the way to do a $http call. Here is the working plunker for the same.
If you observe the $scope.login() function I've injected the service object and invoked the checkAuthentication() function which does the HTTP call.As you are using .then for http calls, angular provides provision to use two functions for success and error callbacks where your HTTP errors go when HTTP calls fail.
Here is the angular doc for the same.
In your example you don't have error callback method hence it doesn't go into your if else conditions.
var app = angular.module("App", []);
app.controller('AppCtrl', ['$rootScope', '$scope', '$http', 'Service', function($rootScope, $scope, $http, Service) {
$scope.login = function(token) {
//call the injected service in the function for HTTP call..
Service.checkAuthentication(token).then(function(response) {
console.log("testing response: " + response);
// if a valid token is already in storage = response contains "Success"(?), just $state.go to main page, else call the login() function
if (response.content === "Success") {
// $state.go main page
}
},function(error){
console.log(error);
console.log("could not log in due to error...");
});
};
}]);
//use angular services to do a http call for better code maintainability...
app.service('Service', ['$http', '$rootScope', function($http, $rootScope) {
return {
checkAuthentication: function(token) {
return $http.get("http://validUrl/test", {
headers: {
'testingAuth': token
}
});
}
};
}]);
Firstly, apology if this question does not make sense. I am developing code for session management for my mean stack app. From last few days, i found lots of way to implement it which are using either cookies, sessions or http - headers. I tried to implement, but did not get success.
I successfully link the interceptor with my code. Code is listening to each req/res.
Here is some code:
app.js
angular.module('MyApp', [
'ngMaterial',
'ngMdIcons',
'ui.router',
'e3-core-ui.services',
'e3-core-ui.utils'
])
.config(['$stateProvider', '$routeProvider','$httpProvider','$mdThemingProvider', '$mdIconProvider', function($stateProvider, $routeProvider, $httpProvider, $mdThemingProvider, $mdIconProvider) {
$httpProvider.interceptors.push('YourHttpInterceptor');
...
Interceptor-code
angular.module('MyApp')
.factory('YourHttpInterceptor', ['$q',
function($q, ) {
return {
'request': function(config) {
console.log("req");
return config;
},
// Optional method
'response': function(response) {
// do something on response success
console.log("inside the response ");
return response;
},
// optional method
'responseError': function(rejection) {
// Here you can do something in response error, like handle errors, present error messages etc.
console.log("inside the response error ");
return $q.reject(rejection);
}
};
}]);
I will be very thankful for your time and help.
In Meanjs you have the authentication controller
mean/modules/users/client/controllers/authentication.client.controller.js
but if you want to use the authentication service in your interceptor, just be aware that injecting a dependency isn't that easy as doing it in a controller.
you'll need to use $injector
var AuthService = $injector.get('Auth');
then you'll have to be sure your user is authenticated and check that in your request function, something like
if (!Authentication.user) {
$location.path('/'); // or a login page
}
I'm very new to Angular, so it's perfectly possible I made some stupid mistakes.
What I'm trying to do is use a token that is saved in localStorage and put that in all requests.
I have this code block:
.config(['$httpProvider', 'localStorageService', function($httpProvider, localStorageService) {
//Http Interceptor to check auth failures for xhr requests
$httpProvider.interceptors.push('authHttpResponseInterceptor');
$httpProvider.defaults.useXDomain = true;
$httpProvider.defaults.headers.common.Authorization = 'Token token=' + localStorageService.get("TemponiaToken")
}])
And I'm getting this error message:
Uncaught Error: [$injector:modulerr] Failed to instantiate module starter due to:
Error: [$injector:unpr] Unknown provider: localStorageService
I found this question and answer which (I think) explains the problem: Why can't I use the localStorage in my .config when it's include in the .module definition?
However: how can I solve this? Change the .config into .run ? Thanks for any pointers in the right direction.
As the answer you found says is not possible to inject services during the config phase.
There are two possible solution to your problem.
The first one is to use the native localStorage object
localStorage.getItem("TemponiaToken") // it just works without injecting any service
The other one is to correctly define the interceptor
yourApp.factory('AuthInterceptor', function (localStorageService) {
return {
request: function (config) {
config.headers = config.headers || {};
config.headers.Authorization = 'Token token=' + localStorageService.get("TemponiaToken")
return config;
}
};
});
yourApp.config(function ($httpProvider) {
$httpProvider.interceptors.push('AuthInterceptor');
});
The documentation of ngStorage says thus:
Usage from config phase
To read and set values during the Angular config phase use the .get/.set functions provided by the provider.
var app = angular.module('app', ['ngStorage'])
.config(['$localStorageProvider',
function ($localStorageProvider) {
$localStorageProvider.get('MyKey');
$localStorageProvider.set('MyKey', { k: 'value' });
}]);
I have a single page angular app which calls a RESTish service. How can I configure the base URL for my REST server so that in my services I can use relative URLs? Also, as I was playing around with the following interceptor I got an error where angular-ui router seemed to be using http to get views so this was affected by the middleware. Basically I guess I want a second http service to inject into my services that has this middleware, how can I do this?
app.config(["$httpProvider", function($httpProvider) {
$httpProvider.interceptors.push('middleware');
}]);
app.factory('middleware', function() {
return {
request: function(config) {
// need more controlling when there is more than 1 domain involved
config.url = "http://localhost:8080" + config.url;
return config;
}
};
});
The $http services is very important (and widely used) inside Angular.
You shouldn't alter it like this.
For handling requests to an API, it is best to create a dedicated service (even if it's a wrapper around $http).
E.g.:
.service('API', function ($http) {
var baseUrl = 'http://localhost:8080/';
this.get = function (path, config) {
return $http.get(baseUrl + path, config);
}
...
});
Then you can use your service for all API calls:
.controller('someCtrl', function (API) {
API.get('items').success(function (data) {
$scope.items = data;
});
});
This is a question about template loading customization in $templateCache.
Goal is handling transport layer, exactly:
Ability to modify template url.
Ability to handle transport errors and timeouts.
How can be $templateCache loader modified with custom transport wrapper?
Prefferably at global application level, i.e. directives should't know about this modification.
You could use a $http interceptor for this. You could use the request interceptor to change the URL, and the responseError interceptor to deal with errors. A simple implementation is below, that you would have to change to exactly how you want the URL to be modified and how errors are handled.
app.factory('TemplateInterceptor', function($injector, $window, $q, $timeout) {
return {
'request': function(config) {
// Test if is a template
var isTemplate = config.url.match(new $window.RegExp("^/?templates/"));
// Save in config, so responseError interceptor knows
config.TemplateInterceptor = config.TemplateInterceptor || {};
config.TemplateInterceptor.isTemplate = isTemplate;
if (isTemplate) {
config.url = '/modified-url' + config.url;
}
return config;
},
'responseError': function(rejection) {
// Avoid circular dependency issues
var $http = $injector.get('$http');
// If a template, then auto-retry after 1 second
return !rejection.config.TemplateInterceptor.isTemplate
? $q.reject(rejection)
: $timeout(angular.noop, 1000).then(function() {
return $http(rejection.config);
});
}
}
});
Registered as:
app.config(function($httpProvider) {
$httpProvider.interceptors.push('TemplateInterceptor');
});