-
Notifications
You must be signed in to change notification settings - Fork 3k
Added a $stateNotFound event which can prevent or redirect state transitions. #414
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
Conversation
Nice. It would be cool to do the parallel behavior in urlRouter to support url based laziness. |
|
I guess thats true if one's otherwise rule for laziness does its own version of retrying once and only once. |
@nateabele could you give this a quick once-over to see if it looks about right (or grossly wrong)? I need to get |
Added docs for rule as param with otherwise(). https://github.com/angular-ui/ui-router/wiki/URL-Routing#otherwise-for-invalid-routes |
I'd love to see some more example code on how you might use the handler for real. The redirect param is a tad confusing to me. |
@eahutchins At first pass I was pretty much ready to merge it, but I spent another couple hours chewing on it, and I have three thoughts. I pulled down and applied the patch and started playing with it a bit. I kind of started questioning the need for a I took one of your tests and rewrote it a bit, and the end result was effectively the same. Take a look and let me know what you think about this style: it('can be redirected in $stateNotFound', inject(function ($state, $q, $rootScope) {
initStateTo(A);
$rootScope.$on('$stateNotFound', function ($event) {
$state.transitionTo(D, { x: '1', y: '2' });
$event.preventDefault();
});
var promise = $state.transitionTo('never_defined', { z: 3 });
$q.flush();
expect($state.current).toBe(D);
expect($state.params).toEqual({ x: '1', y: '2' });
})); Also, as @timkindberg mentioned, I'd very much like to see an example of how you're using this to do lazy-loading, since event-handling is synchronous (for my own understanding as well as the docs). If this is only a stepping-stone to the goal, let's work on figuring out how we can give Finally, since (well, if) we're making everything fully asynchronous, I wonder if it'd make more sense to convert the remainder of the errors to transition rejections. I can see arguments on both sides, but it really comes down to whatever we discover for deferred loading of states. Anyway, looking forward to your thoughts. I think we're really close to a really clean solution, and at this point, this problem has become important enough that I'm holding the next release until we can solve it. |
@timkindberg, @nateabele I added a simple lazy-definition test case, it turns out in our case we're currently bouncing through |
What if the event included a parameter that is, by default, an empty function... and what if event handlers could overwrite the empty function with their own function... and that function were then called by transitionTo using $q.when...? The idea being that the event handler can insert a promise into the processing and have that promise respected by transitionTo prior to retrying. |
@stu-salsbury you mean a function returning a promise? Presumably this is only happening from the immediately prior event call so why not just put a promise into the event itself? I could see something like this sort-of working:
|
Well I was thinking that if someone wanted to do something that wasn't a promise, then $q.when would allow for that -- so if you called the property retryCallback instead of retryPromise, and used $q.when to resolve it, then that's kinda what I meant. |
@stu-salsbury how would you handle the fall-through case where the handler was able to define the state? If I understand you correctly the retry path would always be recursive in your case (if my transition check actually works maybe that's fine). |
I haven't fully grokked your code. In detour what I do is recurse on transitionTo after trying the promise, but I set a flag that I'm on retry so I don't retry a second time. |
In detour I know that getLazyState returns a promise, so it's different.
|
…defer state lookup retry.
@stu-salsbury I added |
@nateabele I'm not terribly happy with the We could move the redirect parameter last to keep a similar event API, but there is the confusing aspect that the input $rootScope.$broadcast('$stateNotFound', to, toParams, from.self, fromParams, redirect); this might be more confusing in the end. |
Please don't take this as confrontational, but does anyone really need to redirect from a named state in this manner? Couldn't they just prevent the default and do whatever they want including go to some other state? I figured this was just a sneaky way to get lazy loading in! :) |
@stu-salsbury I agree that the |
Actually I just don't like calling it $scope.$on('$stateNotFound',
function(event, unfoundState, fromState, fromParams){ ... }) I'm good with it if we rename it. |
@timkindberg that's a much better name, I'll change it. |
I also think the properties on the unfoundState object should be 'name', 'params' and 'options'; not 'to', 'toParams' and 'options'. |
One thing I wanted to mention earlier is not to get too hung up on the naming here. One of the things we have slated for later (probably around 0.4.0) is rewriting all state events to take one parameter, which will be an object representing the current transition, so whatever we do here is an interim solution that will ultimately be going away. At that point, doing another |
Added a $stateNotFound event which can prevent or redirect state transitions.
@timkindberg the event handler can set a |
@eahutchins I considered adding it but thought that we should just make a full FAQ section for lazy loading. Would you be able to write the FAQ on how to lazy load states? I was going to take a stab at it, but I don't want to mislead by writing it incorrectly. I've created the spot for it already. https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-lazy-load-states |
I would really like to see that FAQ updated by someone on the team. Ping @eahutchins =) |
As of now the best way to understand how this might work is to look at the src changes and tests over on the files changed tab above. |
Added a
$stateNotFound
event which can be prevented (in which casetransition aborted
is returned with no error thrown), or redirected by substituting theredirect
event argument with the desired target state and params. In the latter case the state lookup is always retried once (even when not redirected), potentially allowing lazy-definition of state.The
$stateNotFound
handler looks like:where
redirect
contains the originalto
,toParams
andoptions
arguments totransitionTo
, allowing any/all of those arguments to be altered.