I would like to point out that there should not be any problems accessing the /settings path, since it does not correspond to any state if you have not used inherited states (see below).
The actual problem occurs when accessing the path /settings/ , because it will assign an empty string ( "" ) to the id parameter.
If you have not used inherited conditions
Here is the solution in plunker for the following problem:
access to the path /state_name/ when there is a state with url /state_name/:id
Decision explanation
It works through the onBefore hook ( UI router 1.x or higher) transition service, which prevents the transition to states with missing required parameters.
To declare what parameters are needed for the state, I use the data hash as follows:
.state('settings', { url: '/settings/:id', data: { requiredParams: ['id'] } });
Then in app.run add hook onBefore :
transitionService.onBefore({}, function(transition) { var toState = transition.to(); var params = transition.params(); var requiredParams = (toState.data||{}).requiredParams || []; var $state = transition.router.stateService; var missingParams = requiredParams.filter(function(paramName) { return !params[paramName]; }); if (missingParams.length) { return $state.target("home", {alert: "Missing params: " + missingParams}); } });
If you used legacy conditions
You can implement the same logic through inherited states:
function router($stateProvider) { $stateProvider .state('settings', { url: '/settings' }) .state('settings.show", { url: '/:id' }); }
you need to add the abstract property to the parent declaration to make the /settings path unavailable.
Decision explanation
This is what abstract state documentation describes :
The abstract state can never be directly activated. Use an abstract state to provide inherited properties (url, resolve, data, etc.) For child states.
Decision:
function router($stateProvider) { $stateProvider .state('settings', { url: '/settings', abstract: true }) .state('settings.show", { url: '/:id' }); }
Please note: this only solves the problem with /settings path, and you still need to use the onBefore hook solution to also restrict access to /settings/ .