How to redirect using ajax in angularjs - angularjs

I want to redirect a user on specific page using ajax call in angularjs. I am able to redirect using below mentioned code but when i again want to redirect user to root page i am unable to do so as the value of $window.location.href+ 'getTechnicianWorkOrder/'+woId is persisting as is:
$scope.getTechnicianWorkOrderFormURL = function(woId){
return $window.location.href + 'getTechnicianWorkOrder/'+woId;
};
Another place where i want to redirect to root page:
$scope.getAssignedListURL = function(){
return $window.location.href;
};
Note: i want to make this redirection work even in offline mode of HTML5 cache-manifest.

Using the $location service.
$location.path('/');

The answer by #prashant-palikhe is the right one, $location.path('/'); is the route to your root path. just use the dependency of $location to your controller like this:
yourapp.controller('YourController', ['$location', function($location) {
...
}
I always use the ui.router for my routes and in there you can add $urlRouterProvider.otherwise('/') for fallback in any unknown state or route.
In some cases you can add something like this in your states:
resolve : {
dataObj : ['$http', function($http) {
return $http({method : 'GET', url : '/your/ajax/endpoint'})
;}],
},
onEnter : ['dataObj', '$state', function(dataObj, $state) {
// dataObj is your ajax response object. Based on this you can redirect to a certain state of needed
$state.go('default');
}]
resolve is data that preloads data onEnter is called before entering the state. This can be used as some sort of middleware.

Related

How do I check for login or other status before launching a route in Angular with routeProvider?

Let's say I have 4 routes - 2 require the user to be logged in, 2 do not. My app init looks like:
$routeProvider.when('/open1',{templateUrl:'/open1.html',controller:'Open1'});
$routeProvider.when('/open2',{templateUrl:'/open2.html',controller:'Open2'});
$routeProvider.when('/secure1',{templateUrl:'/secure1.html',controller:'Secure1'});
$routeProvider.when('/secure2',{templateUrl:'/secure2.html',controller:'Secure2'});
Routes /open1 and /open2 are open to all, while routes /secure1 and /secure2 require the user to be logged in and, if not, take some action, e.g. redirect to login or launch a warning. I can determine the user's state by using my Auth service and calling, e.g., Auth.isLogin(). So the result would be:
going to /open1 and /open2 always go to the template and controller declared above
if Auth.isLogin() returns true, /secure1 and /secure2 go to the above-declared template and controller
if Auth.isLogin() returns false, /secure1 and /secure2 take some other action, e.g. $location.path('/login')
I could put logic in the Secure1 and Secure2 controllers that checks, but that is repetitive and mixes up responsibilities, makes them harder to test, etc.
Is there a way that I can use the $routeProvider to declare, "check this route and this route and if not, redirect"? I was thinking of using resolve somehow, but not quite sure how to work it in (docs on resolve are not very clear, and few helpful examples).
EDIT:
based on the answers below, it appears there are three philosophies for doing this:
Using resolve to check logged in and fail the promise, and then catching the $routeChangeError event to redirect http://www.sitepoint.com/implementing-authentication-angular-applications/
Using just $routeChangeStart event to check logged in and redirect http://arthur.gonigberg.com/2013/06/29/angularjs-role-based-auth/
Using just resolve to check logged in and redirect http://midgetontoes.com/blog/2014/08/31/angularjs-check-user-login
The 2nd option is what the two answerers have suggested.
As in my comments above, there are 3 different paths (plus the ability to use a directive if you want to control it from within html templates). I ended up following
https://midgetontoes.com/angularjs-check-user-login/
which essentially is as follows:
$routeProvider.when('/secure', {
templateUrl: '/secure.html',
controller: 'Secure',
resolve:{
loggedIn:onlyLoggedIn
}
});
And then onlyLoggedIn:
var onlyLoggedIn = function ($location,$q,Auth) {
var deferred = $q.defer();
if (Auth.isLogin()) {
deferred.resolve();
} else {
deferred.reject();
$location.url('/login');
}
return deferred.promise;
};
Simple, works like a charm. If I ever need a directive, I will pull this piece into a service.
This blog post deals with user authentication in AngularJS using directives.
The $route service emits $routeChangeStart before a route change.
If you don't use directives, you can catch that event by calling app.run (you can place it after the code where you define the routes [app.config]). For example:
For full disclosure I use ui.router and this is an adapted code from $stateChangeStart I use in my app
var app = angular.module('app');
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/open1',{templateUrl:'/open1.html',controller:'Open1'});
$routeProvider.when('/open2',{templateUrl:'/open2.html',controller:'Open2'});
$routeProvider.when('/secure1',{templateUrl:'/secure1.html',controller:'Secure1'});
$routeProvider.when('/secure2',{templateUrl:'/secure2.html',controller:'Secure2'});
}]);
app.run(['$rootScope', '$location', 'Auth', function($rootScope, $location, Auth) {
$rootScope.$on('$routeChangeStart', function(event, currRoute, prevRoute){
var logged = Auth.isLogin();
//check if the user is going to the login page
// i use ui.route so not exactly sure about this one but you get the picture
var appTo = currRoute.path.indexOf('/secure') !== -1;
if(appTo && !logged) {
event.preventDefault();
$location.path('/login');
}
});
}]);
I had the same problem and I did it this way:
var app = angular.module('myModule',["ui-bootstrap"]);
And then listen for a locationchange in the app (this will also trigger onEnter of a page)
app.run(function ($rootScope, $location, $cookieStore) {
$rootScope.$on("$locationChangeStart", function (event, next, current) {
//Here you can check whatever you want (servercall, cookie...)
});
}
I Hope this helps!

Angular UI Router - Compulsory URL parameter?

I have a couple of states the use the same controller. Some of these do not require a URL parameter while some do. How do I avoid a state from being accessible if the URL parameter is not provided?
Example:
I have 2 views or states, list and single. They both share the same controller. I have the routes mapped as follows:
state: app.list
url: /list
controller: appCtrl
state: app.single
url: /single/:id
controller: appCtrl
Now, I want single to be accessed only if the id is specified, other wise redirect to some other page. How is that possible using the same controller?
Approach 1
You can use $urlRouterProvider with when() for redirection.
app.config(function($urlRouterProvider){
// when there is an single route without param, redirect to /list
$urlRouterProvider.when('/single/:id', ['$match', '$state', function($match, $state) {
if($match.id === ""){
$state.transitionTo("app.list");
}
}
]);
});
Working demo: http://plnkr.co/edit/sEoUGGCEge0XbKp3nQnc?p=preview
Approach 2
You can check the param in controller side and redirect it to specific page
myApp.controller('MainCtrl', function($state, $stateParams) {
if($state.current.name == 'app.single' && $stateParams.id === ""){
$state.transitionTo("app.list");
}
});
Working demo: http://plnkr.co/edit/QNF1RHy4Prde4CRhNLFa?p=preview
Note: In the above demos, redirection works when your current state should not be app.single. Means, State will not change if you are in app.single state and trying without param. So go to main page, then click the link without param of single state. it will redirect to list state.

How to multilingual url when user enter, copy paste or click url from other website

I have angularjs project implemented multi-language and using ui-router for routing. Every language will be have different url. Ex:
http://example.com/!#/en-us/english-title
http://example.com/!#/es-es/spanish-title
All state with url registered automatically when app run and load them from database. Ex:
angular.module('bxApp').run(["$http", function ($http) {
$http.get('/Home/Routes').success(function (result) {
result = result || {};
if (angular.isDefined(result) && result !== null) {
_.each(result.Routes, function (route) {
stateProvider.state(route.Name, {
url: route.Url,
templateUrl: route.TemplateUrl,
controller: route.Controller,
});
});
}
});
}]);
It work well but it will not work when user copy this link and paste to browser or click this link from other website . I think because of state can't found so it will be redirect to default and it does not keep url that user enter or copy.
In this case , How to do that?
Thanks,
You're declaring your states as a result of an HTTP call to your server: the problem is that these states are defined too late for the user to navigate to them when he pastes the URL in a new tab.
To understand, let's deconstruct what happens :
The user is on the initial page / other website, and copies the URL.
He pastes it in a new tab
Your angular application loads, finishes its config phase without having declared any of those states, and sends an HTTP call.
ui-router fails to route to a state matching the pasted URL, since the corresponding state is not here yet, and redirects to default
The HTTP response comes back, and your states are created (but too late).
How to make it work ?
My first reaction would simply not to store your states on your server. Unless you want the very core of your UX to be language-dependent, you don't have to do that.
But hey, let's say we want to do it anyway. I suggest you try this : declare a toplevel 'language' state, and have it load the other states in a resolve clause. This will 'block' the routing until the other states are declared :
angular.module('bxApp')
.config(['$urlRouterProvider', function ($urlRouterProvider) {
$urlRouterProvider
.state('language',{
url: '/:language',
resolve: {
childrenLoaded: ['$http', function ($http) {
// returning a promise is essential to have the 'waiting' behavior
return $http.get('/Home/Routes').then(function (data) {
var result = data.result || {};
if (angular.isDefined(result) && result !== null) {
_.each(result.Routes, function (route) {
$stateProvider.state(route.Name, {
url: route.Url,
templateUrl: route.TemplateUrl,
controller: route.Controller
});
});
}
});
}]
}
})
}]);
Again, this approach is probably asking for trouble : I strongly recommend you hardcode your states instead of storing them in a database. If all that varies from one language to another is the text and URL, then you will be fine with an URL param.

Angular - Logout redirect route

I am trying to create a route that clears the users session and redirects them back to the root homepage.
.config(function config( $routeProvider, $stateProvider ) {
$routeProvider.
when('/logout', {resolve: {redirect: function(Session){
Session.clear();
return "/home";
}}});
I'm obviously doing something wrong here, as calling
$location.path("/logout");
... ignores the function and redirects back to the default route. I've tried adding console.log statements to the function to see if it is being called.
Am I using the redirect function incorrectly?
Have you considered putting your logout logic in a separate controller? Would be a little cleaner, more robust, & make redirection more straightforward. Like so:
function LogoutController($location) {
Session.clear();
$location.path('/home');
}
The your route is:
when('/logout', {
template: '', //A template or templateUrl is required by AngularJS, even if your controller always redirects.
controller: 'LogoutController'
}).
I had the same issue and what I did instead was create a logout function in my navigationController that gets hit when the URL is clicked
<li>Log Out</li>
And in my navigationController:
$scope.logout = function () {
localStorage.clearAll();
window.location = '/logout';
};
I'm running ASP.NET behind Angular so I needed the browser (not angular) to route to /logout which is mapped in ASP.NET config (does a few other session clean ups and redirects to authentication app)
Hope this helps
just store the $sessionStorage (username) then delete the the $sessionStorage (username) ..
$scope.logout = function(){
delete $sessionStorage.sessname; //sessname is get sessionStorage username
$location.path('/login');
};
help me for this link:https://stackoverflow.com/questions/36056745/angularjs-click-logout-button-to-clear-sessionstorage-again-and-again-go-back-to
I use this approach
$routeProvider
.when('/logout', {
resolve: {
logout: ['authService', function (authService) {
authService.clear(true);
}]
}
})

Check if user is logged in before template load

I use angularjs with ui-router library. Lets say I have some routes for admin and some routes for user. If admin or user is logged in I want to show some page for them (admin.html for admin and user.html for user, for example), otherwise login.html
On the backend I have a special url, like /auth/status/, which gives me information about the user (if he's logged and which role he has)
There are some situations I can't figure out how to handle:
I go to '/' url. The application loads. I have a run method for my app module. But how can I check if the user is logged in, when it happens asynchronously? Well, I have this and it works somehow, but I'm not sure if this is a good solution:
app.config(['$stateProvider', '$routeProvider',
function($stateProvider, $routeProvider) {
$stateProvider
.state('admin', {
abstract: true,
url: '/',
templateUrl: 'templates/admin.html'
})
.state('admin.desktop', {
url: 'desktop',
templateUrl: 'templates/desktop.html'
});
}]);
app.run([
'$http',
'$rootScope',
'$location',
'$state',
'userRoles',
function($http, $rootScope, $location, $state, userRoles) {
var DEFAULT_ADMIN_STATE = 'admin.desktop';
var promise = $http.get('/auth/status/');
promise.then(function(response) {
$rootScope.isLogged = response.data.logged;
$rootScope.userRole = userRoles[response.data.role];
if (!$rootScope.isLogged) {
$state.transitionTo('login');
} else {
switch (response.data.role) {
case 'admin': $state.transitionTo(DEFAULT_ADMIN_STATE); break;
}
}
}, function(response) {
$location.path('/login');
});
}]);
Though I don't understand: if I go to / url I should get an error because it's abstract. Instead when $http.get request is resolved (I put 2 seconds sleep in backend to check that) I transition to admin.desktop state. I'm confused what happens in which order: state loads template or app.run function with some ajax requests...
The main question is, when I go to /#/desktop how can I first check if user is logged (send a request to /admin/auth/ and check what it returns) and only then decide what to do (transition to login or desktop state)?
I found Delaying AngularJS route change until model loaded to prevent flicker this, but again still a little fuzzy for me. Resolve property seems like a solution when I want to load a list of entities and then show the template. But I want to have some "before" function for ALL states which just checks if user is logged and has a correspond role (one moment: I do not want to use /admin/entites or /user/entities urls, want to have just /entitites. As I get it several states may have the same url). So basically it looks like if I go to /someurl I want to run method wait until it gets ajax response and after that transition to some state. Instead the state corresponding to /someurl load a template...
Also I found an article about authentication in angular but author uses cookies which is not async thing
Update: when I use cookies for checking if user is logged and I go to /#/desktop I still have it rendered, and $state.transitionTo doesn't work..
You should check it before page load:
I cannot write full example now, but in common you should do like this:
.run([ ..., function(....) {
$scope.$on('$routeChangeStart', function(next, current) {
... check cookie here ...
});
}]);

Resources