I'd like to point out that there shouldn't be any problem with accessing the /settings
path, since it doesn't correspond to any state, unless you've used inherited states (see below).
The actual issue should happen when accessing the /settings/
path, because it will assign the empty string (""
) to the id
parameter.
If you didn't use inherited states
Here's a solution in plunker for the following problem:
accessing the /state_name/
path, when there's a state with url /state_name/:id
Solution explanation
It works through the onBefore hook (UI router 1.x or above) of the Transition service, which prevents transitioning to states with missing required parameters.
In order to declare which parameters are required for a state, I use the data
hash like this:
.state('settings', {
url: '/settings/:id',
data: {
requiredParams: ['id']
}
});
Then in app.run
I add the onBefore
hook:
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) {
/* returning a target state from a hook
issues a transition redirect to that state */
return $state.target("home", {alert: "Missing params: " + missingParams});
}
});
If you used inherited states
You could implement the same logic via inherited states:
function router($stateProvider) {
$stateProvider
.state('settings', {
url: '/settings'
})
.state('settings.show", {
url: '/:id'
});
}
then you'd need to add the abstract
property to the parent declaration, in order to make /settings
path inaccessible.
Solution explanation
Here's what the documentation says about the abstract states:
An abstract state can never be directly activated. Use an abstract state to provide inherited properties (url, resolve, data, etc) to children states.
The solution:
function router($stateProvider) {
$stateProvider
.state('settings', {
url: '/settings',
abstract: true
})
.state('settings.show", {
url: '/:id'
});
}
Note: that this only solves the issue with /settings
path and you still need to use the onBefore hook solution in order to also limit the access to /settings/
.