How to handle http 302 response in angularjs - javascript

I have a java filter, that checks session attribute username. When the username is null then redirect to path /login.I access path /index.html when username is null, I got a HTTP code 302, so I add interceptor in angularjs. But I access /index.html got a error when username is null.
var testApp = angular.module('testApp', [ 'ngRoute', 'myApp' ]);
testApp.config([ '$routeProvider', function($routeProvider) {
$routeProvider.when('/anchor/historyAttendance/:uid',{
templateUrl : 'anchor/historyAttendance.html',
controller : 'AnchorHistoryAttendanceCtrl'
}).when('/anchor/list', {
templateUrl : 'anchor/list.html',
controller : 'AnchorListCtrl'
}).otherwise({
redirectTo : '/'
});
} ]);
var app = angular.module('myApp', [ 'ngTable', 'ngFileUpload', 'ngDialog' ,'ui.colorpicker', 'ngCsv', 'ngSanitize'],function ($provide,$httpProvider) {
// register the interceptor as a service
$provide.factory('myHttpInterceptor', function($q) {
return {
// optional method
'request': function(config) {
// do something on success
console.log(config);
return config;
},
// optional method
'requestError': function(rejection) {
// do something on error
console.log(rejection);
return $q.reject(rejection);
},
// optional method
'response': function(response) {
// do something on success
console.log(response);
return response;
},
// optional method
'responseError': function(rejection) {
// do something on error
console.log(rejection);
return $q.reject(rejection);
}
};
});
$httpProvider.interceptors.push('myHttpInterceptor');
});
app.directive('fontColor', function () {
return {
restrict: 'E',
scope: {},
replace: false,
template: '<div color-picker default-color="#ff0000" class="font-color" ng-style="{\'background-color\': selectedFontColor}"></div>',
link: function (scope) {
scope.selectedFontColor = '#f00';
scope.$on('colorPicked', function (event, color) {
scope.selectedFontColor = color;
});
}
}
});
the error in chrome like that:

You can not handle 302 response from a server because browsers do this before the Angular is notified. In a way, Angular response interceptor will never get a hand on this response.
It is properly explained here: Handle HTTP 302 response from proxy in angularjs or https://stackoverflow.com/a/29620184/2405040

It seems that you have created myApp after creation of testApp while you have injected myApp with testApp which does not look correct.
Make sure before injecting any of the module it should be available.
Try below code:
var app = angular.module('myApp', [ 'ngTable', 'ngFileUpload', 'ngDialog' ,'ui.colorpicker', 'ngCsv', 'ngSanitize'],function ($provide,$httpProvider) {
// register the interceptor as a service
$provide.factory('myHttpInterceptor', function($q) {
return {
// optional method
'request': function(config) {
// do something on success
console.log(config);
return config;
},
// optional method
'requestError': function(rejection) {
// do something on error
console.log(rejection);
return $q.reject(rejection);
},
// optional method
'response': function(response) {
// do something on success
console.log(response);
return response;
},
// optional method
'responseError': function(rejection) {
// do something on error
console.log(rejection);
return $q.reject(rejection);
}
};
});
$httpProvider.interceptors.push('myHttpInterceptor');
});
app.directive('fontColor', function () {
return {
restrict: 'E',
scope: {},
replace: false,
template: '<div color-picker default-color="#ff0000" class="font-color" ng-style="{\'background-color\': selectedFontColor}"></div>',
link: function (scope) {
scope.selectedFontColor = '#f00';
scope.$on('colorPicked', function (event, color) {
scope.selectedFontColor = color;
});
}
}
});
var testApp = angular.module('testApp', [ 'ngRoute', 'myApp' ]);
testApp.config([ '$routeProvider', function($routeProvider) {
$routeProvider.when('/anchor/historyAttendance/:uid',{
templateUrl : 'anchor/historyAttendance.html',
controller : 'AnchorHistoryAttendanceCtrl'
}).when('/anchor/list', {
templateUrl : 'anchor/list.html',
controller : 'AnchorListCtrl'
}).otherwise({
redirectTo : '/'
});
} ]);

Related

RouteProvider resolve AngularJS

Here is my code :
Js:
angular.module('main', [])
.config(['$locationProvider', '$routeProvider',
function($locationProvider, $routeProvider) {
$routeProvider.when('/tables/bricks', {
controller: "myController",
resolve: {
"check" : function($location){
if(!$scope.bricks) {
$route.reload();
}
}
},
templateUrl: 'tables/bricks.html'
});
$routeProvider.otherwise({
redirectTo: '/tables/datatables'
});
}
])
.controller('myController', function($scope, $location, $http) {
var vm = this;
$scope.Bricks = function(){
$location.path('/tables/bricks');
};
vm.getbricks = function(n){
var url = n;
$http({
method: 'GET' ,
url: url,
})
.then(function successCallback(data) {
$scope.bricks = data.data;
console.log($scope.bricks);
}, function errorCallback(response) {
console.log(response);
console.log('error');
});
};
});
HTML:
<button ng-click="vm.getbricks(n.bricks_url);Bricks();"></button>
After click the button in html, my page goes into /tables/bricks, but nothing happend, because resolve probably is wrong. What I want - that i could go to /tables/bricks only then, when $scope.bricks exist, so only when vm.bricks() will be called.
Thanks for answers in advance!
I think your problem is that the vm.getbricks will always return something (in success or error handler), so will never be falsy, and you will always call the Bricks() constructor. try to return true on success callback and false in error callback.
$scope is for controllers, which it can't reach in the config. Instead, you should be returning something from a service, which will be called during your resolve. E.g. if(YourService.getbricks())
Solution: move your logic from a controller into a service. And make sure to return a value from it that can be checked in the config.
app.service('BrickService', function() {
this.getbricks = function(url) {
return $http.get(url) // return the Promise
.then(function(response) {
return response.data; // return the data
}, function(error) {
console.log(error);
});
};
});
With this you can inject the service into the config and run its function.
angular.module('main', [])
.config(['$locationProvider', '$routeProvider',
function($locationProvider, $routeProvider) {
$routeProvider.when('/tables/bricks', {
controller: "myController",
resolve: {
"check": function(BrickService) { // inject
if ( BrickService.getbricks() ) { // run its function
$route.reload();
}
}
},
templateUrl: 'tables/bricks.html'
});
$routeProvider.otherwise({
redirectTo: '/tables/datatables'
});
}
])
You can also use the loaded values in the controller after they have been resolved. For that, you would need to simply return it. So change the logic to this:
resolve: {
"check": function(BrickService) { // inject
var bricks = BrickService.getbricks(); // run its function
if ( bricks ) {
$route.reload();
}
return bricks; // return the result (note: it's not a Promise anymore)
}
}
Then you can inject this resolve into your controller:
.controller('myController', function($scope, $location, $http, check) {
var vm = this;
vm.bricks = check;
...
(Note check was added)

$resource is not changing the id of the url

I am in trouble to change the id param of a URL passed to $resource. Apparently the value isn't changing to the correct value that it recive from Resource.get(id:$routeParams.id), even when I put a fixed value (Resource.get(id:1)), resulting in the following error:
TypeError: encodeUriSegment is not a function
When I change the id param of the URL for a fixed value (baseURL+'client/1'), it works.
This is my font:
app.js
'use strict';
angular.module('serviceOrder',['ngRoute','ngResource'])
.config(function ($routeProvider,$locationProvider) {
/*$locationProvider.html5Mode({
enabled: true,
requireBase: false
});*/
$routeProvider.when('/clients', {
templateUrl: 'views/clients.html',
controller: 'ClientController'
});
$routeProvider.when('/newclient',{
templateUrl: 'views/client.html',
controller: 'NewClientController'
});
$routeProvider.when('/editclient/:id',{
templateUrl: 'views/client.html',
controller: 'EditClientController'
});
$routeProvider.otherwise({redirectTo: '/clients'});
});
controler.js
'use strict';
angular.module('serviceOrder')
.controller('EditClientController',['$scope','$routeParams','clientService',
function ($scope,$routeParams,clientService) {
$scope.message = 'Loading ...';
$scope.client = {};
$scope.phone = {id:'',brand:'',model:'',state:'',esn:''};
debugger;
clientService.getClients().get({id:$routeParams.id})
.$promise.then(
function (response) {
$scope.client = response;
},function (error) {
$scope.message = 'Error: ' + error;
}
);
}]);
service.js
'use strict';
angular.module('serviceOrder')
.constant('baseURL', 'http://localhost:8080/service-order-rest/rest/')
.service('clientService',['$resource','baseURL',function ($resource,baseURL){
this.getClients = function () {
return $resource(baseURL+'client/:id',null,{'update':{method:'PUT'}});
};
}]);
Your param defaults are not being configured properly. To achieve this, according to $resource's docs, you must especify the pattern of your API method that will receive params like { id: '#id' } instead of null.
$resource(baseURL + 'client/:id', //url
{ id: '#id' }, // parameters
{
'update': { method: 'PUT' } // methods
});
We have a bug here :
return $resource(baseURL+'client/:id',{id: youridhere} ,{'update':{method:'PUT'}});

Do $http request from Angular Interceptor?

I'm trying to implement Angular Interceptor for Exceptions. For one at least. I have a token and when it old enogh backend throws TokenAlmostExpired exception. This exception contains errorCode = 101. In the interceptor I'm checking that code is 101 and then I need to send POST request to backend's /refresh endpoint so I could refresh token.
.factory('errorInjector',['$injector', function ($q, $injector) {
var vm = this;
var errorInjector = {
'response': function (response) {
console.log(response);
return response;
},
'responseError': function (rejection) {
if (JSON.stringify(rejection.data.errorCode) === JSON.stringify(101)) {
vm.getRefreshToken();
}
return $q.reject(rejection);
}
};
return errorInjector;
}]);
and
.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push('errorInjector');
}]);
$http
But there's a problem at interceptor level, that I can't just give it dependency on $http, because there's Circular dependency found: $http <- errorInjector <- $http <- $templateFactory <- $view <- $state
$scope
And I can't put getRefreshToken() function to $scope, because $scope dependency also gives 'Circular dependency'.
$Injector
var http = $injector.get('$http');
doesn't work as well, and gives me erorr.
So how can I catch exception in interceptor and then do a $http request from there?
Interceptor
(function (angular) {
'use strict';
angular.module('services').factory("httpInterceptor", [
'errorLauncher',
'$q',
function (errorLauncher, $q) {
return {
'requestError': function (rejection) {
if (rejection.status === 101) {
errorLauncher.pushInErrorMessage(rejection);
}
return $q.reject(rejection);
},
'responseError': function (rejection) {
if (rejection.status === 101) {
errorLauncher.pushInErrorMessage(rejection);
}
return $q.reject(rejection);
}
};
}]);
})(angular);
and error handler service
(function (angular) {
'use strict';
angular.module('services').factory("errorLauncher", [
'$rootScope',
function ($rootScope) {
return {
'pushInErrorMessage': function (rejection) {
$rootScope.$emit('theTokenWillDieSoon');
}
};
}]);
})(angular);
and now main app controller
(function (angular) {
'use strict';
angular.module('controllers').controller("globalCtrl", [
'$rootScope',
'$http',
function ($rootScope, $http) {
$rootScope.$on('theTokenWillDieSoon', function () {
// http from here
});
}]);
})(angular);
.factory('errorInjector',['$injector', function ($q, $injector) { .... }]);
Change To:
.factory('errorInjector',['$q', function ($q) { .... }]);
So I've done it with service. Thanks everyone!
interceptor:
.factory('errorInjector',['$injector', function ($q, $injector) {
var errorInjector = {
'response': function (response) {
....
},
'responseError': function (rejection) {
if (JSON.stringify(rejection.data.errorCode) === JSON.stringify(101)) {
var refreshTokenService = $q.get('refreshTokenService');
refreshTokenService.refreshTokenService();
$.notify({message: data.data.detailMessage}, {type: 'warning'});
}
return $q.reject(rejection);
}
};
return errorInjector;
}]);
refreshTokenService:
.service('refreshTokenService', ['$http', function ($http) {
this.refreshTokenService = function () {
$http.post('/refresh').then(
function success(response) {
.....
},
function error(data) {
.....
}
);
};
}])
;

Inject controller in $routeProvider resolve method

Following the main answer here, I've tried to do the same, with the exception that my controller is isolated.
I get this:
Uncaught Error: [$injector:modulerr] Failed to instantiate module myApp due to:
ReferenceError: myController is not defined
I only get this when the resolve: parameter is present.
How can I work around this one ?
Route config:
.state("my.jobs", {
url: "/my/:jobId",
templateUrl: "Views/my/index.htm",
controller: "myController",
resolve: myController.resolve // the root of all evil here
})
controller:
(function (ng, app) {
"use strict";
var ctrl = app.controller(
"myController",
['$scope', 'job',
function ($scope, job) {
$scope.job = job;
}]);
ctrl.resolve = {
job: function ($q, $stateParams, batchService) {
var deferred = $q.defer();
jobService.loadJob($stateParams.jobId, true)
.then(deferred.resolve, deferred.reject);
},
delay: function ($q, $defer) {
var delay = $q.defer();
$defer(delay.resolve, 1000);
return delay.promise;
}
};
})(angular, myApp);
I don't want to make the controller a global function, I like it isolated as it is.
In your case you could create one service, that you can consume inside your resolve function.
app.factory('resolveService', ['$q', '$stateParams', 'batchService','jobService',function($q, $stateParams, batchService,jobService ) {
return {
job: function($q, $stateParams, batchService) {
var deferred = $q.defer();
jobService.loadJob($stateParams.jobId, true).then(deferred.resolve, deferred.reject);
return delay.promise;
},
delay: function($q, $defer) {
var delay = $q.defer();
$defer(delay.resolve, 1000);
return delay.promise;
}
}
}]);
Then the config code will be
.state("my.jobs", {
url: "/my/:jobId",
templateUrl: "Views/my/index.htm",
controller: "myController",
resolve: {
resolveService: "resolveService" //this resolves to a service
}
});
For more info look at this reference

Heroku + Rails + Angular [$injector:nomod]

I'm having a problem with an angular.js/rails application, working locally, that results in a js crash on Heroku.
To allow for local testing, I downloaded and placed all angular.js files in the vendor directory. I'm not using any gems, simply placing the angular files in the asset pipeline so that the individual controller coffeescript files can use the angular library.
This is my app.js:
angular.module('generosity', ['ngRoute', 'templates'])
.config(['$routeProvider', '$locationProvider',
function($routeProvider, $locationProvider) {
$routeProvider.
when('/', {
templateUrl: "users-form.html",
controller: 'UsersController'
}).
// when('/phones/:phoneId', {
// templateUrl: 'partials/phone-detail.html',
// controller: 'PhoneDetailCtrl'
// }).
otherwise({
redirectTo: '/'
});
$locationProvider.html5Mode(true);
}])
.controller('UsersController' ['$scope', '$http', '$rootScope', function($scope, $http, $rootScope) {
var self = this;
self.username;
self.realName;
self.password;
self.availableHours; //How should this be styled?
self.currentCity;
self.currentLocation;
self.recipient; //Should probably be renamed
$scope.errCode = 0;
self.addUser = function() {
var errCode;
$http.post('users/add', {username: self.username, password: self.password}).
success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
var errCode = data.errCode;
self.retrieveErrCode(errCode);
// console.log("HYA" + self.errCode);
if(errCode == -2) {
alert("Error: This username already exists.");
}
else if(errCode == -3) {
alert("Error: The username is empty, too long, or has invalid characters.");
}
else if(errCode == -4) {
alert("Error: The password is empty, too long, or has invalid characters.");
}
else {
alert("User created.");
}
console.log(errCode);
$rootScope.errCode = data.errCode;
}).
error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
alert("Error.");
});
console.log(self.username);
return $scope.errCode;
}
self.retrieveErrCode = function(code) {
$scope.err = code;
console.log("here");
};
self.createDummyUser = function() {
self.username = "LordChristopher";
self.realName = "Lord Christopher";
self.password = "Team 61C";
self.availableHours = "6 to 11 pm";
self.currentCity = "Berkeley";
self.currentLocation = "Nowhere";
self.recipient = "He whose name shall not be spoken";
};
// self.login = function(name, pw) {
// };
// self.logout = function() {
// };
}])
.controller('SessionController', ['$scope', '$http', '$rootScope', function($scope, $http, $rootScope) {
var self = this;
self.userId;
self.username;
self.login = function(username, password) {
$http.post('login', {username: username, password: password}).
success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
alert("Connected");
console.log("connected");
}).
error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
console.log("error");
alert("Error.");
});
}
}])
.directive('navbar', function() {
return {
restrict: 'E',
templateUrl: "navbar.html"
};
})
.directive('usersForm', function() {
return {
restrict: 'E',
scope: {
},
templateUrl: "users-form.html"
};
})
.directive('loginForm', function() {
return {
restrict: 'E',
scope: {
},
templateUrl: "login-form.html"
};
})
.directive('usersTests', function() {
return {
restrict: 'E',
scope: {
},
templateUrl: "users-tests.html"
};
})
// .directive('directiveA', function() {
// return {
// restrict: 'A',
// scope: {
// name: '#',
// hobby: '#'
// },
// templateUrl: "example-module.html"
// };
// }) //Only put a semi-colon on the last directory of the module
.directive('css1', function() {
return {
restrict: 'C',
link: function(scope, element, attrs) {
element.css("width", 400),
element.css("font-style", "oblique");
element.css("color", "green");
element.css("font-size", "30px");
}
};
})
.directive('testStatus', function() { //You do not need to account for the cases for which the rating is not a number.
return {
restrict: 'C',
scope: {
message: '#'
},
link: function(scope, element, attrs) { //Note that this is a function of scope, NOT $scope!!
if(scope.message.search("PASS") > 0) {
element.css("color", "green");
}
else if(scope.message.search("FAIL") > 0) {
element.css("color", "red");
}
else {
element.css("color", "blue");
}
}
};
})
It runs just fine locally, using Rails s. However, despite my best efforts (all the "serve static assets:true" in config/assets/production.rb, and several add-on gems that auto-minify js files for production) heroku returns the following stacktrace:
Uncaught Error: [$injector:modulerr] Failed to instantiate module generosity due to:
Error: [$injector:nomod] Module 'generosity' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
http://errors.angularjs.org/1.3.0/$injector/nomod?p0=generosity
at https://still-plains-1604.herokuapp.com/assets/application-b623e3dc11cb731dd5e417203ceb10d1.js:5:20793
at https://still-plains-1604.herokuapp.com/assets/application-b623e3dc11cb731dd5e417203ceb10d1.js:5:28971
at e (https://still-plains-1604.herokuapp.com/assets/application-b623e3dc11cb731dd5e417203ceb10d1.js:5:28543)
at https://still-plains-1604.herokuapp.com/assets/application-b623e3dc11cb731dd5e417203ceb10d1.js:5:28855
at https://still-plains-1604.herokuapp.com/assets/application-b623e3dc11cb731dd5e417203ceb10d1.js:6:4062
at o (https://still-plains-1604.herokuapp.com/assets/application-b623e3dc11cb731dd5e417203ceb10d1.js:5:21178)
at h (https://still-plains-1604.herokuapp.com/assets/application-b623e3dc11cb731dd5e417203ceb10d1.js:6:3840)
at _e (https://still-plains-1604.herokuapp.com/assets/application-b623e3dc11cb731dd5e417203ceb10d1.js:6:5485)
at Q.s (https://still-plains-1604.herokuapp.com/assets/application-b623e3dc11cb731dd5e417203ceb10d1.js:5:26814)
at Q (https://still-plains-1604.herokuapp.com/assets/application-b623e3dc11cb731dd5e417203ceb10d1.js:5:27124)
http://errors.angularjs.org/1.3.0/$injector/modulerr?p0=generosity&p1=Error…com%2Fassets%2Fapplication-b623e3dc11cb731dd5e417203ceb10d1.js%3A5%3A27124) application-b623e3dc11cb731dd5e417203ceb10d1.js:6
For clarity, "generosity" is the name of the app itself, which was defined in app.js.
Why would the module I defined be impossible to find in production, and not in local?
The app can be found at https://still-plains-1604.herokuapp.com/ literally any help with this issue would be a godsend.
Your source has a couple issues.
The HTML has two data-ng-app tags.
The angular-route file, which seems necessary for the app, isn't there.

Categories

Resources