-
Notifications
You must be signed in to change notification settings - Fork 3k
Feature: Default sub-state for abstract states #1235
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 agree. |
I have also been trying to get this to work since I need to route to the first item in a collection returned from the server. I have it working with the above work around, however I'm not sure what the best way to handle routing back to the parent state when the user is already at a child state. It also looks like you don't need to listen for route changes. controller: function($scope, $state, recordList) {
$scope.recordList = recordList;
if (/parentState$/.test($state.current.name)) {
$state.go('.childState', { id: recordList[0].id });
}
} |
+1 |
Thanks for raising this @ProLoser. I have now come across the need for this feature a few times and would be great to see in ui-router. |
The idea is sound. I have also come across this requirement. |
+1 |
Instead of, or perhaps in addition to having a default child state for an abstract state, I would like to see a |
Perhaps, however I would normally prefer to see that logic located in a function defined as the value of the abstract key: abstract: function(resolvedItem) {
// do checks here on resolvedItem
return 'abstractParent.defaultChild';
}
// or
abstract: 'abstractParent.defaultChild' However there's no reason the event couldn't be added as a redundancy |
The problem with the above is that the function is declared in the context of the module.config callback, into which a very limited set of services ($providers specifically and most notably no actual services) can be injected. Such a function would not have access to any of the normal application state that it would need in the course of executing its decision tree. |
@kbaltrinic no idea what you're talking about, it would work almost exactly like how resolves work. In fact it'd probably fall under the resolve chain. Resolves fire at runtime, there's no reason this wouldn't either. |
.state('parent', {
// ...
url: '/project/:id',
resolve: {
project: function($http, $stateParams) {
return $http({ url: '/project/' + $stateParams.id });
}
},
abstract: function(project){
return (project.started) ? '.begin' : '.dashboard';
}
}) |
Ah, I see what you are thinking now. It had not occurred to me that the abstract function would have access to the resolve dependencies or be injectable, though in retrospect I suppose it makes sense that it would be. Yes, in that case the function should work for all our cases. |
👍 |
+1 |
2 similar comments
+1 |
+1 |
would ❤️ to have it, too |
👍 |
1 similar comment
👍 |
Any progress made on this one? |
@acollard That's pretty close to what I'm thinking. In ui-router-extras I've added a similar option for default substate, using
|
@getvega Thanks, that's an interesting use case that I hadn't considered. |
@christopherthielen If this was built into the framework you wouldn't need the '$stateChangeStart' event hookup and you could fully support injectable services. Personally I prefer "redirectTo" over "default". Since redirect better explains what is happening. "Default" could be useful for another function anyways. My suggestion is to support something like this. .config(['$stateProvider', '$urlRouterProvider',function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('Account.Security', {
url: '/security',
redirectTo: 'Account.Security.ChangePassword', // OR
redirectTo: ['$state', 'authenticationService', function($state, authenticationService){
var currentUser = authenticationService.user();
if(currentUser)
$state.go('Account.Security.ChangePassword', { userId: currentUser.id });
else
$state.go('Account.Login');
}]
});
}]); This is obviously a contrived example, I wouldn't put the userId in a stateParam. It would be pulled in as a resolve on the Account.Security.ChangePassword state. |
Great suggestions @christopherthielen & @acollard . +1 on But I tend to prefer @christopherthielen's usage ( |
@getvega My thinking is it would support both string and function similar to ngRoute configuration (ex template: {string=|function()=}). But I like @christopherthielen idea for including the params too. So maybe redirectTo could be 3 different options:
I agree with your point about the function being too close to onEnter. But my reason for keeping it is I would like redirectTo support on abstract states and onEnter shouldn't fire for an abstract state in my opinion. |
I'd like some comments on 1) what meaning does what meaning does
|
You guys are quick 👍 I hadn't even typed my questions up yet! Paging @ProLoser and @nateabele |
@christopherthielen I'm with you on 3,6,7 per my last post. I prefer the name 'redirectTo' over just 'redirect'. More inline with ngRoute. To help all those people who move to ui-router from ngRoute...:smile: |
@acollard fair enough. Truth is, I've never even looked at ngRoute, so I had no idea |
Honestly, food for thought: what does having an 'abstract' flag gain you? I am pretty sure I had somewhere I was going with this... I agree having abstract + redirect doesn't make sense, but I was thinking On Mon Feb 09 2015 at 9:07:55 AM Chris Thielen [email protected]
|
@ProLoser That's my line of thinking too. I think lots of people assume Once you mix in redirect, however, it becomes nothing more than a marker, as you mentioned. |
@christopherthielen 👍 on this scenario; sometimes we use abstract states only to define a common layout and context highlighting (auth is really good example). The whole idea of abstract states is pretty natural if you ask me. I vote for keeping the |
@christopherthielen I go with @inca Keep abstract flag and add redirectTo or redirect as mentioned by you |
@inca so you would have a state that you can never go to and it never redirects? That would make things like ui-sref harder methinks |
In the spirit of the parameter discussion, I also used to use something like this that was broken in 0.2.13 and am unsure how to work around it:
|
@nalroff Doesn't state-based redirection work for that use case?
See this comment: #948 (comment) |
@christopherthielen That's perfect. Thanks! Not sure how I missed that. |
@eddiemonge Sorry, missed your comment (didn't receive an email). Yup, just like @christopherthielen mentioned an abstract Another question arises, however: say, state with provides resolves and controllers, but redirects to non-inherited state. Will they be available in a state you've been redirected too? Or state redirection is implemented separately from inheritance? |
@inca the concepts are separate. A redirect is essentially a totally different transition starting from the same "from" state. The redirect happens before resolves are even processed on the "redirecting state". |
Hate asking, but is there a milestone or pre-release which includes this fix? I desperately need it :) |
@inca I can't speak to when this feature will be added. But in the meantime you could use the implementation I described in #1584. We've been using this for a while and it works great. module.run(['$rootScope', '$state', '$injector', function ($rootScope, $state, $injector) {
$rootScope.$on('$stateChangeStart',function (event, toState, toParams) {
var redirect = toState.redirectTo;
if (redirect) {
if (angular.isString(redirect)) {
event.preventDefault();
$state.go(redirect, toParams);
}
else {
var newState = $injector.invoke(redirect, null, { toState: toState, toParams: toParams });
if (newState) {
if (angular.isString(newState)) {
event.preventDefault();
$state.go(newState);
}
else if (newState.state) {
event.preventDefault();
$state.go(newState.state, newState.params);
}
}
}
}
}); |
Closing this in the interest of consolidating discussion on #27 (but will keep it around for reference). |
As per this discussion: https://github.com/ProLoser/AngularJS-ORM/issues/12
It would be cool if abstract states could have a default sub-state. Lets say
project
is an abstract state. However, instead of being unable to go directly to it, if you DO go directly to it, you automatically get pushed into a substate (such asproject.tasks
). This should probably handle either a string or an injectable callback function.Otherwise I have to do crap like this:
If you simply do the check once when the controller loads, then going from
project.whatever
toproject
doesn't re-execute the controller and therefore the check isn't performed again. If you put this logic earlier (such as in aresolve
oronEnter
) then the (async?) call to$state.go
will restart the entire resolve resolution process since the route never finished loading, which causes an endless loop (unless you add toState checks in, yadda yadda).Long story short, I think this is an excellent idea and I approve this message.
The text was updated successfully, but these errors were encountered: