-
Notifications
You must be signed in to change notification settings - Fork 3k
Bug in duplicate state name checking when using 'parent' definitions #368
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I don't consider this a bug... Your assumption that an explicit parent gets normalized into dot notation is incorrect. The opposite is true in that dot notation is used to infer parent if it is not explicitly provided, but this doesn't actually change the state name. Having $state silently change the name could be rather confusing... as it stands the name you register is the same name you can use for $state.transitionTo, $state.is, or anywhere else a state is referred to by name. |
IMO this is a docs issue. @timkindberg It doesn't look like we have docs on this. Showing the different ways to define states/parents should probably be right on the main wiki page. |
Oh it's always the docs guy's fault. I see how this works. jk. I have a whole page dedicated to Nested States, granted its the second page in the guide, but I personally feel that first you need to learn how to make a single state and its properties before you move on to nesting multiple states. What am I missing? Should I just add an intro to that page about the 3 explicit ways to create nested states? |
So I added some stuff to the docs. Hopefully it helps clear this up a bit. https://github.com/angular-ui/ui-router/wiki/Nested-States-&-Nested-Views |
I found this quite surprising, in effect for options 2 and 3 you need to name the states using dot notation to have equivalent navigation even though you aren't specifying the actual relationship that way? This is counter-intuitive and makes designing reusable components that much more of a pain (you have to catenate state names based on which parent state you attach to). This is extra confusing if state-relative addressing (in |
I don't think it's right either. We'll have to think of a solution. |
yeah, the relative addressing via sref and go() have obviously somewhat changed expectations... I think it's important to have the ability to "move" sub-trees of the state tree (i.e. a reusable or semi-independent component) around in the tree by only changing the definition of the root of that sub-tree, without having to touch all the other states or changing every ui-sref etc. |
Sorry, I didn't fully digest this the first time around. Object states not resolving to fully-qualified names behind the scenes is obviously wrong.
Yeah, there's actually an issue there that I have to fix, so that |
I disagree on this one... If define a state and tell $state that it is called "foobar", then I should be able to $state.transitionTo('foobar') and have a ui-sref="foobar" no matter what parent state I decide to hang "foobar" off. |
Maybe we can work out the 'relative' name of a state at registration time in addition to the absolute name... If the parent is inferred from dot-notation, the relative name becomes the part after the last dot. Or another option would be to do it the other way around -- we DO derive an absolute name, but we still use the name as it is specified as an alias for the fully qualified name, as long as the alias is unique (and once it's no longer unique you just can't refer to the state via the alias anymore). Not ideal either though because it means stuff can break via changes at a distance. |
Makes sense to me. |
@ksperling IMO state references should always be "fully-qualified" meaning that for object-defined states, use the object, and for strings, use the dot-separated path. As you mentioned, |
Good to see the discussion on this issue. I'm sure you guys will choose a good solution. For whoever might find this interesting, currently I use the following helper functions for my state configuration: function setState(state){
fixStateName(state);
$stateProvider.state(state);
if(state.children && state.children.length){
state.children.forEach(function(childState){
childState.parent = state;
setState(childState);
});
}
}
function fixStateName(state){
var name = state.name;
var currentState = state;
while(currentState.parent !== undefined){
currentState = currentState.parent;
name = currentState.name + '.' + name;
}
state.name = name;
} My application has one
This allows for some powerful state related stuff. For example creating menus. MainMenu: <li ng-repeat="state in rootState.children | filter:{ data.inMenu: true }" ng-class="{ selected: $state.includes(state) }"> SecondaryMenu: angular.module('MyApplication.controllers')
.controller('SecondaryMenuController', ['$scope', '$rootScope', '$state', function($scope, $rootScope, $state){
$scope.getSecondaryState = function(){
for(var i = 0; i < $rootScope.rootState.children.length; i++){
var secondaryState = $rootScope.rootState.children[i];
if($state.includes(secondaryState)){
return secondaryState;
}
}
};
}]); <li ng-repeat="state in getSecondaryState().children" ng-class="{ selected: $state.includes(state) }"> |
@ksperling what happens when I define a reusable component with a state |
+1 on fixing this. I think that using different state configuration options should not change the available navigation API. Especially since I find the first option for defining states names extremely tedious (apparent when you start having many nested states) |
|
@H0 would you mind fixing it? It is a wiki after all. |
I have created a simple module with my helper function, ui-router.stateHelper. With this helper you can easily define nested states by using |
@marklagendijk that's awesome... wonder if we should roll that into ui-router somehow... I could at least add a link to your repo in the guide. |
I think this ship has long since sailed. The name used to register the state is the name you use to reference the state (in, e.g., "Dot notation" in a state name implicitly chooses the parent state. It's now an error to specify a parent using dot notation and using the I.e., this is an error: .state({
name: 'home.foo',
parent: 'home'
}) It should either be
or
|
Currently there are 3 ways of defining states:
name: 'contacts.list'
parent: 'contacts'
parent: contacts
(where 'contacts' is an stateObject)What you would expect is that method 2 and 3 would resolve the name to the 'dot notation'. However, currently this doesn't seem to happen. Because of this the code which checks for duplicate stateNames wrongfully throws errors when 2 children of different parents have the same name.
For example:
Or object notation:
Both throw an error:
While defining this example using method 1 does work:
The text was updated successfully, but these errors were encountered: