ui-router adding trailing slash at end of route causing 404 - angularjs

I've built out an application and mostly everything is working as expected except I have these three states where when I refresh the page via reloading the url it causes a trailing slash on the end of the page causing my otherwise('/404') to trigger.
This happen nowhere else on the entire platform. The weird part is that if I change the state URL for one of the states with issues, the issue is fixed.
The three state url's that have issues are market, refer-business and invite-friends. These are all a child of a shell view named root. I have absolutely no idea what is causing this issue.
I also realized that if I take $urlRouterProvider.otherwise('/404'); out of my main modules config, the issue goes away as well.
Here are two of the routes that aren't working.
market.routes.js
function marketRoutes($stateProvider) {
$stateProvider.state('market', {
parent: 'root',
url: '/market?category', // If I change this to /blahblah, it works perfects
views: {
"#root": {
templateUrl: '/market/market.html',
controller: 'MarketController',
controllerAs: 'MarketCtrl'
}
},
resolve: {
Categories: ['MarketService', function (MarketService) {
return MarketService.getCategories();
}],
Products: ['MarketService', '$stateParams', function (MarketService, $stateParams) {
// By default the market should open on `deals of the moment` category
return MarketService.getProducts(0, 9, 1, $stateParams.category || 4);
}]
},
data: {
title: 'Market'
}
});
}
refer-business.routes.js
function ReferBusinessRoutes($stateProvider) {
$stateProvider.state('refer-business', {
parent: 'root',
url: "/refer",
templateUrl: "/refer-business/refer-business.html",
controller: "ReferBusinessController",
controllerAs: "rbCtrl",
onEnter: function () {
this.data.title = "Refer a business";
},
data: {
title: 'Refer a business'
},
authenticate: true
});
}
I've spent the last 3 days on this and I've come up with nothing. Hopefully somebody here has run into this issue or has some tips on how to further debug it.

You might find the answer here: Handling trailing slashes in angularUI router
Explains How to tell angular deal with trailing slashes as usual.
It also might be permission problem in your template files at server side

Related

angularjs 1.x - stateProvider ignoring url property

I have an application with a main state and a child state. I do have the url property set but it seems angular it is ignoring it, but it is not ignoring the optional parameter at the end, which is correctly populated. Please see below code snippet. (to be honest, this application always worked but after an update in the Siemens product this particular feature is not behaving correctly, but at the end of the day this is an angular app, so I am not sure how they could have changed globally this behavior if you have an idea I will be very happy to check that). thanks
this is the main page:
function config($stateProvider) {
var item = {
name: "Carriers",
//ShippingAndReceiving is ignored, but /:direction is correclty attached to the URL
url: '/ShippingAndReceiving/:direction',
views: {
'Canvas#': {
templateUrl: folder + '/carrierOverview.html',
controller: 'CarrierOverviewController',
controllerAs: 'vm'
}
},
data: {
title: 'Vehicles'
},
params: {
reload: null,
carrier: null,
direction: null,
arriving: null
}
};
$stateProvider.state(item);
}
this is the child page:
function config($stateProvider) {
var item = {
name: 'Carriers.Details',
url: '/RegisterVehicle',
};
$stateProvider.state(item);
}
both the pages load correctly and everything works properly, but the URL does not change, it is constantly "Carriers" for both pages.
I do not have any extra unnecessary $state.go anywhere.
this is the call to browse to the page:
$state.go('Carriers.Details');

Populate route params with resolved data in angular ui-route

Give the following code:
$stateProvider
.state('app.users', {
abstract: true,
url: '/users',
templateUrl: 'views/users.html',
resolve: {
userId: Users => Users.lastUserSelected()
},
})
.state('app.users.questions', {
url: '/:userId/questions',
templateUrl: 'views/questions.html',
controller: 'UsersQuestionsCtrl',
resolve: {
questions: (userId) => Questions.getAll(userId)
}
})
When I transit to the app.users.questions state, everything goes ok, but the URL in the browser ends up being like mydomain.com/users//questions (notice the double forward slash // in the route, there's no userId)
Seems like the user ID resolved from the parent state is not populated in child route, or something alike. I think I'm missing a key concept here.
I would like to achieve a URL like mydomain.com/users/USERID/questions.
I've been through many ui-router guides but couldn't figure this out, any help is really appreciated.
I'm populating my sideBar menu using the addMenuItem and addMenuSubItem methods from the MEANJS project.
Menus.addMenuItem('sidebar', {
state: 'app.users',
type: 'dropdown',
iconClass: 'fa fa-comments',
position: 4,
roles: ['*']
});
Menus.addSubMenuItem('sidebar', 'app.users', {
state: 'app.user-questions'
});
Notes:
1- It doesn't matter the previous state, wherever state I come from... it's not related at all to the user, so passing the :userId from all the possible previous states sounds wrong to me. I'm just using USERS and QUESTIONS as an example here but those are not the entities i'm working with in my actual project.
2 - Im using MEANJS seed project

UI Router conflicting when using similar URL pattern

I have the following 2 states defined in my app.config:
state('product-details', {
url: '/products/:productId',
templateUrl: '/pages/product-details/product-details.tmpl.html',
controller: 'ProductDetailsController'
})
and
state('product-register', {
url: '/products/register',
templateUrl: '/pages/product-register/product-register.tmpl.html',
controller: 'ProductRegisterController'
})
The problem I am facing is since both their URL patterns are similar, when I try to navigate to product-register state, the 'register' is interpreted by angularui-router as a productId and redirects me to product-details state instead.
After going through some similar questions on SO, I thought I would filter these URLs using regexes as explained here. But when I tried this, although the regex was matching properly in isolation, the state refused to change.
Then again after doing a bit of research I decided to merge the two states like this:
state('product-details', {
url: '/products/:param',
templateUrl: ['$stateParams', function($stateParams) {
if($stateParams.param === 'register') {
return '/pages/product-register/product-register.tmpl.html';
} else {
return '/pages/product-details/product-details.tmpl.html';
}
}],
controller: ['$stateParams', function($stateParams) {
if($stateParams.param === 'register') {
return 'ProductRegisterController';
} else {
return 'ProductDetailsController';
}
}]
})
This also does not seem to work as expected. What am I missing? Isn't this a very normal thing you would have to do?
Try to move 'product-register' state before 'product-details' state.
Actually you need to differentiate your state URL pattern or else angular will fire the first match it will find.
You should be able to specify types for your parameters to match only certain states.
In your case you could use:
url: '/products/{productId:int}'
There are lots of other examples on the ui router page:
https://github.com/angular-ui/ui-router/wiki/URL-Routing

passing parameter to Angular application state

I have made yoman angular fullstack app setup.
I am making use of ui.router in application.
I have defined state parameters as
.state('tour', {
url: '/tour',
templateUrl: 'app/tour/tour.html',
controller: 'tourCtrl',
params : {tourName: null, },
})
I am able to pass parameter to this state within application.
when my application goes to external link.
I want to get back to one of the state of my angular application with some parameter. so how can i do that??
Please Help me to do that .. Thanks
you can pass parameters and maintain states using stateParams, and then maintaining them in the URL. For your understanding, I have added a plunk:
http://plnkr.co/edit/SDOcGS?p=preview
Observe the console whenever you navigate to Route1 tab, and then observe the code:
.state('route1', {
url: "/route1/:place",
params: {
place: null
},
views: {
"viewA": {
template: "route1.viewA"
},
"viewB": {
template: "route1.viewB"
}
},
resolve :{
place: function($stateParams){
console.log($stateParams);
console.log("url", window.location);
return $stateParams.place;
}
}
})
Try this on localhost. It would work the same way on localhost, or any place where its hosted.

UI-Router - Change $state without rerender/reload of the page

I've been looking at these pages (1, 2, 3). I basically want to change my $state, but I don't want the page to reload.
I am currently in the page /schedules/2/4/2014, and I want to go into edit mode when I click a button and have the URL become /schedules/2/4/2014/edit.
My edit state is simply $scope.isEdit = true, so there is no point of reloading the whole page. However, I do want the $state and/or url to change so that if the user refreshses the page, it starts in the edit mode.
What can I do?
For this problem, you can just create a child state that has neither templateUrl nor controller, and advance between states normally:
// UPDATED
$stateProvider
.state('schedules', {
url: "/schedules/:day/:month/:year",
templateUrl: 'schedules.html',
abstract: true, // make this abstract
controller: function($scope, $state, $stateParams) {
$scope.schedDate = moment($stateParams.year + '-' +
$stateParams.month + '-' +
$stateParams.day);
$scope.isEdit = false;
$scope.gotoEdit = function() {
$scope.isEdit = true;
$state.go('schedules.edit');
};
$scope.gotoView = function() {
$scope.isEdit = false;
$state.go('schedules.view');
};
},
resolve: {...}
})
.state('schedules.view', { // added view mode
url: "/view"
})
.state('schedules.edit', { // both children share controller above
url: "/edit"
});
An important concept here is that, in ui-router, when the application is in a particular state—when a state is "active"—all of its ancestor states are implicitly active as well.
So, in this case,
when your application advances from view mode to edit mode, its parent state schedules (along with its templateUrl, controller and even resolve) will still be retained.
since ancestor states are implicitly activated, even if the child state is being refreshed (or loaded directly from a bookmark), the page will still render correctly.
REF: https://github.com/angular-ui/ui-router/wiki/Quick-Reference#statetransitiontoto-toparams--options
$state.transitionTo('yourState', params, {notify: false});
Adding my answer because I think it's different enough from the accepted answer and may be useful to others:
I had two states, begin and view, with a bunch of optional parameters being synced with the URL for view, like so:
$stateProvider
.state('begin',
{
url: '/',
template: '<app-element></app-element>'
})
.state('view',
{
url: '/View?param1&param2&...&paramN',
template: '<app-element></app-element>'
params: {
param1: {
value: null,
squash: true
},
...
}
});
The link function for <app-element> would run any time I tried to sync the parameters using $state.go. Using {notify: false, reload: false} did not work for me. The link function still ran each time. I'm on 0.2 so dynamic isn't an available param option, either. I followed #b0nyb0y's suggestion and turned it into a parent/child relationship, which worked:
$stateProvider
.state('app',
{
url: '/',
template: '<app-element></app-element>'
})
.state('app.view',
{
url: 'View?param1&param2&...&paramN',
params: {
param1: {
value: null,
squash: true
},
...
}
});

Resources