I am working on angularjs app and my config looks like this:
.config(function($stateProvider,$urlRouterProvider, $localStorage){
$stateProvider
.state('Login',{
url:'/login',
templateUrl:'templates/login.html',
controller:'LoginCtrl',
resolve: {
/* if($localStorage.userInfo === null || $localStorage.userInfo === undefined){
}else{
$scope.signInUser();
}*/
}
})
My login.html looks like this:
<form name="loginform"></form>
I want that if $localstorage.userInfo exists, do not show login.html but call $scope.signInUser function else show the form.
How do I do this using resolve of the route? Can I please get some directions?
I have tried easier ways but I ended up with 10 digest cycles reached error so I was adviced to use resolve for the purpose.
My complete route looks like this:
.config(function($stateProvider,$urlRouterProvider, $localStorage){
$stateProvider
.state('Login',{
url:'/login',
templateUrl:'templates/login.html',
controller:'LoginCtrl',
resolve: {
if($localStorage.userInfo === null || $localStorage.userInfo === undefined){
}else{
$scope.signInUser();
}
}
})
.state('Deployment',{
url:'/deployment',
templateUrl:'templates/deployment.html'
})
.state('Bill',{
url:'/bills',
templateUrl:'templates/bills.html'
})
//$urlRouterProvider.otherwise('/login');
$urlRouterProvider.otherwise(function ($injector) {
var $state = $injector.get('$state');
$state.go('Login');
});
How I achieved this
routes.js
app.config(["$routeProvider", "$locationProvider", function($routeProvider, $location) {
$routeProvider.when("/home", angularAMD.route({
templateUrl: "templates/pages/home.html",
controller: "HomeController",
controllerUrl: "app/controllers/home_controller",
resolve: {
weekendTypes: function(WeekendTypes) {
return WeekendTypes.getAll()
}
}
}));
}]);
factory.js
app.factory("WeekendTypes", ["$http", function($http) {
return {
getAll: function() {
var _apiurl = config_data.GENERAL_CONFIG.AJAX_URL + "weekend/getAll",
promise = $http({
method: "GET",
url: _apiurl
}).success(function(data, status, headers, config) {
return data
});
return promise
}
}
}])
You should use something like this
getData: function(){
var deferred = $q.defer();
$timeout(function(){
var data=localStorageService.get('description'),
deferred.resolve(data);
},3000);
return deferred.promise;
}
Had to try it by myself before sharing code.
Remove the resolve function from set local storage value as data like below
state('Login',{
url:'/login',
templateUrl:'templates/login.html',
controller:'LoginCtrl',
data : {userIfno : $localStorage.userInfo}
})
Then make use of .run function like
.run($rootScope, $state) {
$rootScope.$on('$stateChangeStart', function(toState) {
if (toState.data.userIfno === '') {
$state.go('Login', {}); //here set proper state
}
});
}
Hope this helps you.
Related
I want to verify if the user can access a state before he gets there, if he doesn't have permissions will be redirected to another page.
The problem is that I'm doing a SPA and it verifies the permissions, but it takes a while until the server send the response and the user is redirected, so what happen is that a screen appears for 1 or 2 seconds and then is redirected successfully. Is there anyway to avoid this?
This is the code for the state change:
webApp.run(function ($rootScope, $state, StateService) {
$rootScope.$on('$stateChangeStart', function (event, toState, fromState, toParams) {
StateService.hasAccessTo(toState.name, function(data){
if (data.data != ""){
event.preventDefault();
$state.go(data.data);
}
});
});
});
and the service:
webApp.service('StateService', function($http, $rootScope){
this.hasAccessTo = function(state, callback){
$http.get("state/" + state).then(callback);
}
});
I have also tried with a promise in the $stateChangeStart, but it didn't work.
I read about interceptors, but they work if the user is in another page and access mine, if he is already on the page and type a link manually it doesn't intercepts.
Any modifications or suggestions of new ideas or improvements are welcome!
EDIT
Now I have this:
var hasAccessVerification = ['$q', 'StateService', function ($q, $state, StateService) {
var deferred = $q.defer();
StateService.hasAccessTo(this.name, function (data) {
if (data.data !== '') {
$state.go(data.data);
deferred.reject();
} else {
deferred.resolve();
}
});
return deferred.promise;
}];
$urlRouterProvider.otherwise("/");
$compileProvider.debugInfoEnabled(false);
$stateProvider
.state('welcome',{
url:"/",
views: {
'form-view': {
templateUrl: '/partials/form.html',
controller: 'Controller as ctrl'
},
'#': {
templateUrl: '/partials/welcome.html'
}
},
data: {
requireLogin: false
},
resolve: {
hasAccess: hasAccessVerification
}
})
And it validates, but it doesn't load the template. It doesn't show de views. What might I be doing wrong?
EDIT 2
I forgot to add $state here:
var hasAccessVerification = ['$q', '$state', 'StateService', function ($q, $state, StateService){...}
Consider using the resolve in your state configuration instead of using $stateChangeStart event.
According to the docs:
If any of these dependencies are promises, they will be resolved and
converted to a value before the controller is instantiated and the
$stateChangeSuccess event is fired.
Example:
var hasAccessFooFunction = ['$q', 'StateService', function ($q, StateService) {
var deferred = $q.defer();
StateService.hasAccessTo(this.name, function (data) {
if (data.data !== '') {
$state.go(data.data);
deferred.reject();
} else {
deferred.resolve();
}
});
return deferred.promise;
}];
$stateProvider
.state('dashboard', {
url: '/dashboard',
templateUrl: 'views/dashboard.html',
resolve: {
hasAccessFoo: hasAccessFooFunction
}
})
.state('user', {
abstract: true,
url: '/user',
resolve: {
hasAccessFoo: hasAccessFooFunction
},
template: '<ui-view/>'
})
.state('user.create', {
url: '/create',
templateUrl: 'views/user/create.html'
})
.state('user.list', {
url: '/list',
templateUrl: 'views/user/list.html'
})
.state('user.edit', {
url: '/:id',
templateUrl: 'views/user/edit.html'
})
.state('visitors', {
url: '/gram-panchayat',
resolve: {
hasAccessFoo: hasAccessFooFunction
},
templateUrl: 'views/visitor/list.html'
});
And according to the docs https://github.com/angular-ui/ui-router/wiki/Nested-States-%26-Nested-Views#inherited-resolved-dependencies resolve are inherited:
New in version 0.2.0
Child states will inherit resolved dependencies from parent state(s),
which they can overwrite. You can then inject resolved dependencies
into the controllers and resolve functions of child states.
But, please note:
The resolve keyword MUST be on the state not the views (in case you
use multiple views).
The best practice is to have interceptor on responseError which checks the response status and acts accordingly:
webApp.config(['$httpProvider' ($httpProvider) {
var interceptor = ['$q', '$rootScope', function ($q, $rootScope) {
return {
request: function (config) {
// can also do something here
// for example, add token header
return config;
},
'responseError': function (rejection) {
if (rejection.status == 401 && rejection.config.url !== '/url/to/login') {
// If we're not on the login page
$rootScope.$broadcast('auth:loginRequired');
}
}
return $q.reject(rejection);
}
}
}];
$httpProvider.interceptors.push(interceptor);
}]);
And handle redirection in run block
webApp.run(['$rootScope', function($rootScope){
$rootScope.$on('auth:loginRequired', function () {
$state.go('loginState');
});
}]);
The good thing is that $state service does not need to deal with permission logic:
$stateProvider
.state('someState', {
url: '/some-state',
templateUrl: '/some-state.html',
resolve: {
dataFromBackend: ['dataService', function (postingService) {
// if the request fails, the user gets redirected
return dataService.getData();
}],
},
controller: function ($scope, dataFromBackend) {
}
})
Notice
With this approach, you do not need StateService, all you need to do is to return proper response statuses from backend. For example, if the user is guest, return 401 status.
I am using ajax call to perform functionality in a service file and if the response is successful, I want to redirect the page to another url. Currently, I am doing this by plain JS code window.location = response['message'];. But I need to replace it with AngularJS code. I have looked various solutions on stackoverflow, they used $location. But I am new to AngularJS and having trouble to implement it.
$http({
url: RootURL+'app-code/common.service.php',
method: "POST",
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
dataType: 'json',
data:data + '&method=signin'
}).success(function (response) {
console.log(response);
if (response['code'] == '420') {
$scope.message = response['message'];
$scope.loginPassword = '';
}
else if (response['code'] != '200'){
$scope.message = response['message'];
$scope.loginPassword = '';
}
else {
window.location = response['message'];
}
// $scope.users = data.users; // assign $scope.persons here as promise is resolved here
})
You can use Angular $window:
$window.location.href = '/index.html';
Example usage in a contoller:
(function () {
'use strict';
angular
.module('app')
.controller('LoginCtrl', LoginCtrl);
LoginCtrl.$inject = ['$window', 'loginSrv', 'notify'];
function LoginCtrl($window, loginSrv, notify) {
/* jshint validthis:true */
var vm = this;
vm.validateUser = function () {
loginSrv.validateLogin(vm.username, vm.password).then(function (data) {
if (data.isValidUser) {
$window.location.href = '/index.html';
}
else
alert('Login incorrect');
});
}
}
})();
You can redirect to a new URL in different ways.
You can use $window which will also refresh the page
You can "stay inside" the single page app and use $location in which case you can choose between $location.path(YOUR_URL); or $location.url(YOUR_URL);. So the basic difference between the 2 methods is that $location.url() also affects get parameters whilst $location.path() does not.
I would recommend reading the docs on $location and $window so you get a better grasp on the differences between them.
$location.path('/configuration/streaming');
this will work...
inject the location service in controller
I used the below code to redirect to new page
$window.location.href = '/foldername/page.html';
and injected $window object in my controller function.
It might help you!!
The AngularJs code-sample
var app = angular.module('app', ['ui.router']);
app.config(function($stateProvider, $urlRouterProvider) {
// For any unmatched url, send to /index
$urlRouterProvider.otherwise("/login");
$stateProvider
.state('login', {
url: "/login",
templateUrl: "login.html",
controller: "LoginCheckController"
})
.state('SuccessPage', {
url: "/SuccessPage",
templateUrl: "SuccessPage.html",
//controller: "LoginCheckController"
});
});
app.controller('LoginCheckController', ['$scope', '$location', LoginCheckController]);
function LoginCheckController($scope, $location) {
$scope.users = [{
UserName: 'chandra',
Password: 'hello'
}, {
UserName: 'Harish',
Password: 'hi'
}, {
UserName: 'Chinthu',
Password: 'hi'
}];
$scope.LoginCheck = function() {
$location.path("SuccessPage");
};
$scope.go = function(path) {
$location.path("/SuccessPage");
};
}
I faced issues in redirecting to a different page in an angular app as well
You can add the $window as Ewald has suggested in his answer, or if you don't want to add the $window, just add an timeout and it will work!
setTimeout(function () {
window.location.href = "http://whereeveryouwant.com";
}, 500);
In AngularJS you can redirect your form (on submit) to other page by using window.location.href=''; like below:
postData(email){
if (email=='undefined') {
this.Utils.showToast('Invalid Email');
} else {
var origin = 'Dubai';
this.download.postEmail(email, origin).then(data => {
...
});
window.location.href = "https://www.thesoftdesign.com/";
}
}
Simply try this:
window.location.href = "https://www.thesoftdesign.com/";
The simple way I use is
app.controller("Back2Square1Controller", function($scope, $location) {
window.location.assign(basePath + "/index.html");
});
A good way to do this is using $state.go('statename', {params...}) is faster and more friendly for user experience in cases when you don't have to reload and bootsraping whole app config and stuff
(function() {
'use strict';
angular
.module('app.appcode')
.controller('YourController', YourController);
YourController.$inject = ['rootURL', '$scope', '$state', '$http'];
function YourController(rootURL, $scope, $state, $http) {
$http({
url: rootURL + 'app-code/common.service.php',
method: "POST",
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
dataType: 'json',
data:data + '&method=signin'
}).success(function (response) {
if (response['code'] == '420') {
$scope.message = response['message'];
$scope.loginPassword = '';
} else if (response['code'] != '200') {
$scope.message = response['message'];
$scope.loginPassword = '';
} else {
// $state.go('home'); // select here the route that you want to redirect
$state.go(response['state']); // response['state'] should be a route on your app.routes
}
})
}
});
// routes
(function() {
'use strict';
angular
.module('app')
.config(routes);
routes.$inject = [
'$stateProvider',
'$urlRouterProvider'
];
function routes($stateProvider, $urlRouterProvider) {
/**
* Default path for any unmatched url
*/
$urlRouterProvider.otherwise('/');
$stateProvider
.state('home', {
url: '/',
templateUrl: '/app/home/home.html',
controller: 'Home'
})
.state('login', {
url: '/login',
templateUrl: '/app/login/login.html',
controller: 'YourController'
})
// ... more routes .state
}
})();
Using
location.href="./index.html"
or create
scope $window
and using
$window.location.href="./index.html"
(function () {
"use strict";
angular.module("myApp")
.controller("LoginCtrl", LoginCtrl);
function LoginCtrl($scope, $log, loginSrv, notify) {
$scope.validateUser = function () {
loginSrv.validateLogin($scope.username, $scope.password)
.then(function (data) {
if (data.isValidUser) {
window.location.href = '/index.html';
}
else {
$log.error("error handler message");
}
})
}
} }());
If you want to use a link then: in the html have:
<button type="button" id="btnOpenLine" class="btn btn-default btn-sm" ng-click="orderMaster.openLineItems()">Order Line Items</button>
in the typescript file
public openLineItems() {
if (this.$stateParams.id == 0) {
this.Flash.create('warning', "Need to save order!", 3000);
return
}
this.$window.open('#/orderLineitems/' + this.$stateParams.id);
}
I hope you see this example helpful as it was for me along with the other answers.
I have routes setup like so:
app.config(function($routeProvider) {
$routeProvider
//login
.when("/", {
templateUrl : "framework/views/login.html",
controller : "LoginCtrl",
title: "Login",
authenticate: false
})
//dashboard
.when("/dashboard", {
templateUrl : "framework/views/dashboard.html",
controller : "DashboardCtrl",
title: "Dashboard",
authenticate: true
});
});
Now I want to redirect location changes if authenticate is set to true on the route but a session variable is not true.
For example:
$rootScope.$on("$locationChangeStart", function(event, newURL, oldURL){
if (toState.authenticate && $window.sessionStorage.isLoggedIn) {
$location.path("/");
}
});
This works if I use $routeChangeStart instead, but then I see the next route briefly before it redirects. Location change seems to stop that, but I can't work out how to access the route parameters (i.e. the authenticate parameter).
How do I do this? Or is there a better way entirely?
you should use the resolve parameter within the .when(). This acts as a promise where you can set certain criteria that must be satisfied before the view is rendered. You can find a good demo video here: https://egghead.io/lessons/angularjs-resolve
As I stated in the comment and on demand of Cooper
I post an example:
angular.module('myApp',[])
.factory('httpInterceptor', ['$q', '$location',function ($q, $location) {
var canceller = $q.defer();
return {
'request': function(config) {
// promise that should abort the request when resolved.
config.timeout = canceller.promise;
return config;
},
'response': function(response) {
return response;
},
'responseError': function(rejection) {
if (rejection.status === 401) {
canceller.resolve('Unauthorized');
$location.url('/user/signin');
}
if (rejection.status === 403) {
canceller.resolve('Forbidden');
$location.url('/');
}
return $q.reject(rejection);
}
};
}
])
//Http Intercpetor to check auth failures for xhr requests
.config(['$httpProvider',function($httpProvider) {
$httpProvider.interceptors.push('httpInterceptor');
}])
.config(['$stateProvider',function($stateProvider) {
// states for users
$stateProvider
.state('users', {
abstract: true,
templateUrl: 'users/views/users.html',
resolve: {
issessionedin: function(Sessions){
return Sessions.isLoggedIn();
}
}
})
.state('users.account', {
url: '/user/account/:id',
templateUrl: 'users/views/account.html',
resolve: {
user: function(Users, $stateParams){
return Users.get($stateParams.id);
}
},
controller:'UserAccountController'
})
}])
.factory('Sessions', ['$http',
function($http) {
return{
isSessionedIn :function() {
$http.get('/api/v1/issessionedin');
},
isLoggedIn :function() {
$http.get('/api/v1/isloggedin');
},
hasAccess :function(permission) {
$http.get('/api/v1/hasaccess/'+permission);
}
};
}
]);
of course you need the code server side to return the http status code
Following is my $routeProvider code -
$routeProvider
.when("/login", {
template: JST["app/templates/login"],
controller: "LoginController",
})
.when("/dashboard", {
template: JST["app/templates/dashboard"],
controller: "DashboardController",
resolve:{
getUser: function(UserService) {
return UserService.chkUser()
}
}
})
.otherwise({ redirectTo: function() {window.location = "/login";} });
$locationProvider.html5Mode(true);
});
Following is my UserService code -
angular.module("app").factory("UserService", function($http, $q, User) {
return {
chkUser: function() {
var defer = $q.defer();
defer.resolve(false);
return defer.promise;
// Also tried -
// window.location = "/login";
}
};
});
Problem -
Now when I am navigating to http://example.com/dashboard in a browser I was expected to be logged back at "/login" but I am not, let me know what I am wrong about the resolve usage in angularJS.
Well, your resolve work fine and if you inject getUser into DashboardController, it's value should be false. Because you immediately resolve the promise with false value.
Try something like this:
angular.module("app").factory("UserService", function($http, $q, User, $location) {
return {
chkUser: function() {
var defer = $q.defer();
$http(...., function(user){
if(user){
defer.resolve(user);
}else{
defer.reject();
$location.path('/login');
}
});
return defer.promise;
}
};
});
Or create a fiddle reproducing the problem, so we could have a look and touch that one.
In my HTML, I have the following two links, but when I click them or try to enter them into the browser, my new ui-router code is redirecting them to the otherwise url I have specified. Why is this?
Folders
Clients
//Setting up route
window.app.config(function($stateProvider, $urlRouterProvider) {
// For any unmatched url, redirect to "/"
$urlRouterProvider.otherwise("/asfasfsa");
// Now set up the states
$stateProvider
.state('root', {
url: "/",
templateUrl: 'views/index.html',
resolve: { factory: setRoot }
})
.state('dashboard', {
url: "/dashboard",
templateUrl: 'views/dashboard/dashboard.html',
resolve: { factory: checkAuthentication }
})
.state('folders-show', {
url: "/folders/:folderId'",
templateUrl: 'views/dashboard/folders/view.html',
resolve: { factory: checkAuthentication }
})
.state('clients-list', {
url: "/clients'",
templateUrl: 'views/clients/list.html',
resolve: { factory: checkAuthentication }
})
});
// Check if user is logged in
var checkAuthentication = function ($q, $location) {
if (window.user) {
console.log(window.user);
return true;
} else {
console.log("Not logged in...")
var defered = $q.defer();
defered.reject();
$location.path("/");
return defered.promise;
}
};
// Set Root URLs
var setRoot = function ($q, $location) {
if (window.user) {
var defered = $q.defer();
defered.reject();
$location.path("/dashboard");
return defered.promise;
} else {
return true;
}
};
// Setting HTML5 Location Mode
window.app.config(['$locationProvider',
function($locationProvider) {
$locationProvider.hashPrefix("!");
}
]);
Sorry, simple typos on the folder and clients urls were causing the issue.
Foiled by typos again!