AngularJS ui-router otherwise to state instead of url? - javascript

I am using AngularJS and ui-router and in my app.js. I have the following line:
$urlRouterProvider.otherwise('/');
However I do not want it to send the user to a URL but instead to a state:
.state('404',
{
views: {
'body': {
templateUrl: 'partials/404.html',
}
}
});
Normally I would just do this:
$state.go('404');
How can I do this for the otherwise method?
Note: that my 404 state does not have a URL, so basically it keeps the URL that the user has entered or visited and just changes the template.

I think you achieved that with this code
$urlRouterProvider.otherwise(function($injector, $location){
$injector.invoke(['$state', function($state) {
$state.go('404');
}]);
});

Try This.
$urlRouterProvider.otherwise(function($injector, $location){
$injector.get('$state').go('404');
});

Just a small improvement to #kdlcruz's answer:
$urlRouterProvider.otherwise(function($injector){
$injector.invoke(['$state', function($state) {
$state.go('404', {}, { location: false } );
}]);
});
By doing that, you still able to keep the incorrect the URL and only state is changed.

Related

Pass Json data to another route template in angular js

After login I want to pass the user details to dashboard?How it possible in angular js?
Login.js
mySchoolApp.controller('loginController', ['$scope', '$http', function($scope, $http) {
this.loginForm = function() {
let encodedString = 'uname=' +this.username +'&pwrd=' +this.password;
sessionStorage.user = encodedString;
console.log(sessionStorage.user)
window.location.href = 'dashboard.html';
}
}]);
In console I'm getting the value.
How to get the user details in dashboard.html page?
You should use ng-route to achieve this.Angular isn't designed to work like this
Here is sample
$stateProvider
.state('app', {
abstract: true,
url: "",
template: '<ui-view/>'
})
.state('app.home', {
url: "/",
templateUrl: "partials/main_page.html",
resolve: {
skipIfLoggedIn: skipIfLoggedIn
}
}).state('app.dashboard', {
url: "/dashboard",
templateUrl: "partials/dashboard.html",
controller: 'DashboardCtrl',
activePage:'dashboard',
resolve: {
loginRequired: loginRequired
}
You can store it in a localstorage.So you can use angular-local-storage Angular module for that.
How to set :
myApp.controller('MainCtrl', function($scope, localStorageService) {
//...
function submit(key, val) {
return localStorageService.set(key, val);
}
//...
});
How to Get :
myApp.controller('MainCtrl', function($scope, localStorageService) {
//...
function getItem(key) {
return localStorageService.get(key);
}
//...
});
You should use router module ui-router or ng-router in order to use angualrjs logic in that sense but then your pages are going to be loaded via ajax and regular session http authentication can not be applied.
If that's the case then use angular service provider and let me know to edit my answer.
If you'd like to keep data across pages and not using database or server.
Then what is left as options are: sessionStorage and localStorage.
The localStorage keeps data permanently until browser cache deletes it while the other one obviously for the session.
sessionStorage.setItem('myCat', 'Tom');
If you want to keep js collection like object or array first stringify it:
var user = {pass:'moo', name: 'boo'};
sessionStorage.setItem('userDetais', JSON.stringify(user));

How do I deal with Angular-UI-Router resolve with an unfulfilled promise?

Lets say I have a an angular ui router route set up. When I change to that state, I'm telling Angular that I want it to resolve a factory call first then load the view. But what happens when that api call is empty? I would like to inform the user that there was no results found and stay on at my original state. Not transition to another view with no data to display. What is the best way to achieve this?
The route (which works as expected so far when I know there will be a return)
'use strict';
angular.module('testApp')
.config(function ($stateProvider) {
$stateProvider
.state('spinnerTest', {
url: '/spinner_test',
templateUrl: 'app/spinnerTest/spinnerTest.html',
controller: 'SpinnerTestCtrl',
resolve: {
names: function(NamesService){
//What happens if I return an empty array []?
//How do I return to the previous state?
NamesService.getNames();
}
}
});
});
You can simply reject promise in resolve in case of empty array:
resolve: {
names: function(NamesService) {
return NamesService.getNames().then(function(names) {
return names.length == 0 ? $q.reject('no names') : names;
});
}
}
This is a cross cutting concern, it is probably not unique to the Name service, but other services you are using as well.
Since you didn't post the code to the Name service (NameService service is redundant) I will assume it uses either the $http or $resource service. You can then use a $httpInterceptor that will trigger the display of a message to the user that "The selection is unavailable at this time".
You could call $state.go in your resolve, if you'd like
'use strict';
angular.module('testApp')
.config(function ($stateProvider) {
$stateProvider
.state('spinnerTest', {
url: '/spinner_test',
templateUrl: 'app/spinnerTest/spinnerTest.html',
controller: 'SpinnerTestCtrl',
resolve: {
names: function(NamesService, $state){
//What happens if I return an empty array []?
//How do I return to the previous state?
return NamesService.getNames().then(function(names){
if (!names.length) {
return $state.go('otherState');
}
return names;
});
}
}
});
});

AngularJS: Preventing user from accessing a certain state

I'm building an app using sails.js backend and angular in frontend. I'm trying to prevent the user from accessing the admin control page if he's not authorized. I've run into couple of answers already, but none of them seem to fully work.
At the moment in my app.js, I have
$stateProvider
.state('home', {
url: "/home",
templateUrl: "home/homeTemplate.html",
controller: 'homeController'
})
.state('adminPage', {
url: "/adminPage",
templateUrl: "adminPage/adminTemplate.html",
controller: 'adminPageController',
resolve: {
validate: function($q, $sails, $location) {
var defer = $q.defer();
$sails.get("/user/getCurrentUser")
.success(function(response) {
if (response.user.accessAdminPage) {
defer.resolve();
}
else {
defer.reject("Access blocked");
$location.path('/');
}
return defer.promise;
})
}
}
})
The current code is partially working; The problem at the moment is, that when the unauthorized user first logs in and lands on the home page, and then accesses localhost:1337/#/adminPage, he actually reaches the page. The url in the address bar changes to localhost:1337/#/home but the user isn't redirected. Now the weird part is, when accessing the home page afterwards through the navbar and trying to access the admin page again, the user IS redirected to the home page as intended (although there's an annoying 'flash' while the page is reloaded).
For other people asking, this kind of handling has worked, and I'm wondering what I may have missed and generally any reasons for why my current solution isn't working.
You are returning promise from success function, this will never work.
You should return defered.promise (promise object) from outside success function.
CODE
$stateProvider
.state('home', {
url: "/home",
templateUrl: "home/homeTemplate.html",
controller: 'homeController'
})
.state('adminPage', {
url: "/adminPage",
templateUrl: "adminPage/adminTemplate.html",
controller: 'adminPageController',
resolve: {
validate: function($q, $sails, $location) {
var defer = $q.defer();
$sails.get("/user/getCurrentUser")
.success(function(response) {
if (response.user.accessAdminPage) {
defer.resolve();
} else {
defer.reject("Access blocked");
$location.path('/');
}
});
return defer.promise;
}
}
});
Hopefully this could help you, Thanks.
With the solution given by pankajparkar, the issue is that you will have to reply the logic in each state declaration. I recommend you to check the user's authorization in the onStateChangeStart event
angular.module('myApp', ['ui.router'])
.run(function($rootScope, AuthService){
$rootScope.$on('$stateChangeStart',
function(event, next, nextParams, prev, prevParams) {
AuthService.isNotAutorized()
.then(function() {
event.preventDefault();
$state.go('defaultState');
});
});
});

angular ui-router: get $state info of toState in resolve

Update: this should be possible in angular-ui-router as of 1.0.0alpha0. See the release notes https://github.com/angular-ui/ui-router/releases/tag/1.0.0alpha0 and the issue https://github.com/angular-ui/ui-router/issues/1018 I created.
I would like to access the state's name and other attributes the app is navigating to using angular ui-router when working on the resolve.
The reason: I want load some user data (including their access rights) asynchronously before allowing the app the enter that page.
Currently this is not possible because injecting $state into the resolve points to the state you're navigating away form, not to the one you're navigating to.
I know I can:
get the toState somewhere else with $rootScope('$stateChangeStart') and save it in my settings service for instance. But I think it's a little messy.
hard code the state into the resolve, but I don't want to reuse my resolve for all pages
I also created an issue on the ui-router github (Please + 1 if you are interested!):
https://github.com/angular-ui/ui-router/issues/1018
Here's my code so far. Any help appreciated!
.config(function($stateProvider) {
$stateProvider.state('somePage', {
// ..
resolve: {
userData: function($stateParams, $state, Settings) {
return Settings.getUserData() // load user data asynchronously
.then(function (userData) {
console.log($stateParams);
console.log($state);
// Problem: $state still points to the state you're navigating away from
});
}
}
});
});
Update for Ui-Router 1.x
$provide.decorator('$state', ($delegate, $transitions) => {
$transitions.onStart({}, (trans) => {
$delegate.toParams = trans.params()
$delegate.next = trans.to().name
})
return $delegate
})
Ui-Router 0.x
You can always decorate $state with next and toParams properties:
angular.config(function($provide) {
$provide.decorator('$state', function($delegate, $rootScope) {
$rootScope.$on('$stateChangeStart', function(event, state, params) {
$delegate.next = state;
$delegate.toParams = params;
});
return $delegate;
});
});
And use as such:
.state('myState', {
url: '/something/{id}',
resolve: {
oneThing: function($state) {
console.log($state.toParams, $state.next);
}
}
});
So I discovered the answer to this myself. If you're code is behaving like mine, the $stateParams object is properly injected, but $state is an empty (or old) state object.
What worked for me was referencing this in the resolve function:
.state('myState', {
url: '/something/{id}',
templateUrl: '/myTemplate.html',
controller: function() {},
resolve: {
oneThing: function($stateParams) {
console.log($stateParams); // comes through fine
var state = this;
console.log(state); // will give you a "raw" state object
}
}
})
The first log will return what you'd expect. The second log will return a "raw" (for lack of a better term) state object. So, for instance, to get the state's name, you can access, this.self.name.
I realize this isn't preferred...it would be a lot nicer if $state (or another standardized object) could provide this information for us at the resolve, but this is the best I could find.
Hope that helps...
this.toString() will give you the state name
This has been asked here.
It looks like they built into 1.0.0-rc.2 $state$ which you can inject into the resolve function and get this information.
resolve: {
oneThing: function($state$) {
console.log($state$);
}
}

Angular js - call a route without view

I'm trying calling the /auth/logout url to get redirected after session is deleted:
app.config(['$routeProvider',function($routeProvider) {
$routeProvider
.when('/auth/logout',{
controller:'AuthLogout'
//templateUrl: not needed
})
})
.controller('AuthLogout', ['$window','$location', function ($window,$location) {
$window.localStorage.removeItem('user_username');
$window.localStorage.removeItem('user_id');
$window.localStorage.removeItem('user_session_token');
$location.path('/');
}]);
I actually don't need a view for AuthLogout controller but if I do not specify the templateUrl in routeProvider I can't get this to work, while if I specify a templateUrl it works.
How can I call the url/controller without to having to load a view??
You could do :
.when('/auth/logout', {
controller: function(){
//do staff
}
})
btw may be there is something wrong in your code
because template works and you could exploit it in
the same way
http://docs.angularjs.org/api/ngRoute/provider/$routeProvider
You can use a resolve handler according to the post https://github.com/angular/angular.js/issues/1838
Checkout this quick example and notice the alert statement in resolve.
http://jsfiddle.net/Wk7WD/34/
.when('/detail/:id/', {
resolve: {
load: function ($route, dataService) {
alert("hello");
//Your statements instead of all this which I found in an example
return dataService.load($route.current.params.id);
}
}
})
Instead of the alert you can have your own statements
use redirectTo
app.config(['$routeProvider',function($routeProvider) {
$routeProvider
.when('/auth/logout',{
redirectTo:'/'
})
});
Hope this will work for you :)

Categories