AngularJS ui router mandatory parameters - angularjs

Based on the documentation, angularjs ui-router url parameters are by default optional. So is there a way to create mandatory parameters? Like when the parameter is missing or null it will not proceed to the page?
Hope you can help me.
Thanks

Use UI Routers resolve to check if route params are missing.
//Example of a single route
.state('dashboard', {
url: '/dashboard/:userId',
templateUrl: 'dashboard.html',
controller: 'DashboardController',
resolve: function($stateParams, $location){
//Check if url parameter is missing.
if ($stateParams.userId === undefined) {
//Do something such as navigating to a different page.
$location.path('/somewhere/else');
}
}
})

Above answer prasents incorrect usage of resolve that will fail when code is minified even if annotated. Look at this issue I've spent a lot of time debugging this, because ui-router#0.4.2 won't warn you that resolve should be object.
resolve: {
somekey: function($stateParams, $location){
//Check if url parameter is missing.
if ($stateParams.userId === undefined) {
//Do something such as navigating to a different page.
$location.path('/somewhere/else');
}
}
If you need minification, ngAnnotate

Related

Angular UI Router - How to make a parameter required

$stateProvider.state('state1', {
url:'/state1/:param1/and/{param2:.+}',
templateUrl: 'state1.html',
controller: 'State1Controller',
});
I'm trying to make param2 required by using regex as seen above. If it's empty, then the default state should load:
$urlRouterProvider.otherwise("/");
$stateProvider.state('otherwise',{
url: '/',
templateUrl:'default.html'
});
Now the results:
state1/1/and/1 goes to state1. Good.
state1/1/and goes to otherwise. Good.
But,
state1/1/and/ goes to no state! Neither states are loaded. It's not redirecting back to /. What?!
How do I properly make a parameter required?
Angular js ui-router url parameters are optional by default. For your case above we could make use of $stateParams to check if the required parameter is defined or not. Please check the code below.
if ($stateParams.param2=== undefined) {
// Navigate to home.
$location.path('/');
}
Hope this would solve your issue. Thanks.

How to catch the invalid URL?

I am building a simple HTML site using Angular JS ui-router.
I have built a custom 404 page ('www.mysite/#/error/404'), to which the user is redirected if the user types a url like 'www.mysite/#/invalidUrl'. This functionality was achieved by the following code snippet:
$urlRouterProvider
.when('', '/')
.when('/home', '/')
.otherwise('/error/404');
And the following state snippet:
$stateProvider.state('404', {
parent: 'app',
url: '^/error/404',
views: {
'errorContent#main': {
controller: 'error404Controller',
templateUrl: 'js/general/templates/error404.html'
}
}
});
I am trying to capture the invalid URL requested by the user to be displayed to the user like below.
The URL you requested cannot be found
Request: www.mysite.com/#/invalidUrl
I have tried listening to '$stateNotFound' event, which only seems to be firing when a specific invalid state is requested. I've also tried to listening to events '$stateChangeStart', '$locationChangeStart', and '$locationChangeSuccess' but couldn't find a way to achieve this functionality.
Is this possible? Please, share your thoughts - thank you
Awesome! Thank you Radim Köhler. I don't know how I didn't land on that thread when I searched but that helped me get the answer.
I changed the answer in that thread to fit my scenario which I am going to leave below for reference to any other users.
$stateProvider.state('404', {
parent: 'app',
url: '^/error/404',
views: {
'errorContent#main': {
controller: 'error404Controller',
templateUrl: 'js/general/templates/error404.html'
}
}
});
$urlRouterProvider
.when('', '/')
.when('/home', '/')
.otherwise(function ($injector, $location) {
var state = $injector.get('$state');
state.go('404', { url: $location.path() }, { location: true });
});
So the magic change was the function defined for 'otherwise' option. I didn't change the URL of the 'error' state. Instead, I used the 'state.go' to activate state '404' and passed the location path as the state parameter.
Setting location=true will take you to the URL of the state, and location=false will not. Whichever way you prefer the invalid URL can be accessed easily now.

AngularJS optional route parameter in the beginning

I'm trying to configure my AngularJS app with optional route parameter.
The URLs that I need to support may have a locale at the beginning. e.g.
/fr-FR/Welcome
/Welcome
I tried the following
$routeProvider.when('/:locale?/Welcome', {
...
})
However, it seems, it satisfies the "/fr-FR/Welcome" case and not the "/Welcome" case.
Is it because I'm always prepending a "/" in the beginning.
Will the following work?
$routeProvider.when('/:locale/?Welcome', {
...
})
https://docs.angularjs.org/api/ngRoute/service/$route#example
.config(function($routeProvider, $locationProvider) {
$routeProvider
.when('/Book/:bookId', {
templateUrl: 'book.html',
controller: 'BookController',
resolve: {
}
})
.when('/Book/:bookId/ch/:chapterId', {
templateUrl: 'chapter.html',
controller: 'ChapterController'
});
Also you can use for multiple language support like this tutorials
https://scotch.io/tutorials/internationalization-of-angularjs-applications
It is not possible in Angular.
remember /:locale is not optional. it is route parameter which means its value could be different but it should be there to execute that route (controller and template).
like
/fr/Welcome
/en/Welcome
fr and en must be there which help angular to select that route.

UI Router conditional ui views?

I can't figure out a reasonable way, which doesn't feel like a hack, to solve this rather trivial problem.
I want a guest to see a splash page when they access the index of the website and a logged in user to see their profile, with each page having it's own template and controller. Ideally, there would be two states for one url, and somehow I would be able to automatically alter the active one depending on the loggin status. Both of these views will have their own nested views so ng-include cannot be used (I assume).
I'm quite new to angular and ui router and think I might be overlooking an easy solution to the problem.
Could it be done with named views and ng-show?
If you're using UI Router, just create three states: the root state, with the '/' URL, and two direct descendant states with no URLs. In the onEnter of the root state, you detect the state of the user and transition to the correct child state accordingly. This gives the appearance of keeping the same URL for both child states, but allows you to have to separate states with separate configurations.
The templateUrl can be a function as well so you can check the logged in status and return a different view and define the controller in the view rather than as part of the state configuration
My Solution:
angular.module('myApp')
.config(function ($stateProvider) {
$stateProvider
.state('main', {
url: '/',
controller: function (Auth, $state) {
if (someCondition) {
$state.go('state1');
} else {
$state.go('state2');
}
}
});
});
where state 1 and state 2 are defined elsewhere.
For docs purposes, I used:
$rootScope.$on('$stateChangeStart', function(event, toState) {
if ((toState.name !== 'login') && (!$localStorage.nickname)) {
event.preventDefault();
$state.go('login');
}
});
Using $routeChangeStart didn't work for me.
It is used for me conditional view in ui-route
$stateProvider.state('dashboard.home', {
url: '/dashboard',
controller: 'MainCtrl',
// templateUrl: $rootScope.active_admin_template,
templateProvider: ['$stateParams', '$templateRequest','$rootScope', function ($stateParams, templateRequest,$rootScope) {
var templateUrl ='';
if ($rootScope.current_user.role == 'MANAGER'){
templateUrl ='views/manager_portal/dashboard.html';
}else{
templateUrl ='views/dashboard/home.html';
}
return templateRequest(templateUrl);
}]
});
If I understand the question; you want to make sure that the user who hasn't logged in cannot see a page that requires log in. Is that correct?
I've done so with code like this inside a controller:
if(!'some condition that determines if user has access to a page'){
$location.path( "/login" );
}
Anywhere (probably in some high-level controller) you should be able to just bind a '$routeChangeStart' event to the $rootScope and do your check then:
$rootScope.$on('$routeChangeStart', function(next, current){
if(next != '/login' && !userLoggedIn){
$location.path( "/login" );
}
});
This will get fired every time a new route is set, even on the first visit to the page.
The way I've done this is pretty simple. I made one for our A/B testing strategy. This is the gist:
resolve: {
swapTemplate: function(service) {
// all of this logic is in a service
if (inAbTest) {
this.self.templateUrl = '/new/template.html';
}
}
... other resolves
}
This gets called before the template is downloaded and therefor you're allowed to swap out the template url.
In my case, if two states can share logic of same controller, conditional template is a good choice. Otherwise, creating separate states is a good option.

angularjs ui-router location path not recognizing the forward slahes

I'm using angular ui router / stateProvider. However I set up my url any parts after the second forward slash is ignored and it always sends to this state:
$stateProvider.state('board', {
url: "/:board",
views: {
'content': {
templateUrl: '/tmpl/board',
controller: function($scope, $stateParams, $location) {
console.log('wat')
console.log($location)
}
}
}
});
Which has only 1 forward slash. Even when I go to localhost/contacts/asdf The following state doesn't run.
$stateProvider.state('test', {
url: "/contacts/asdf",
views: {
'main': {
templateUrl: '/tmpl/contacts/asdf',
controller: function () {
console.log('this doesnt work here')
}
}
}
});
This is a console log of $location. As you can see $location only recognizes the last part of the url as the path. As far as I can tell that's wrong. It's missing the "contacts" right before it. Any url is interpreted as having only 1 part for the url and sends to the board state. How do I fix this. THanks.
Edit: found that this was caused by angular 1.1.5. Reverting back to 1.1.4 didn't have this.
This may be the cause: https://github.com/angular/angular.js/issues/2799 . Try adding a base href.
Looks like that fixed in AngularJS v1.0.7. Just tested it.

Resources