Closed legomind closed 10 years ago
You can use a custom regex for the parameter if you use curly brace (JAX-RS style) sytax:
url: '/{username}{page:(?:/[^/]+)?}'
Note that in this case the '/' preceding the optional segment is going to be part of the 'page' value. We could look at allowing capture of a specific part of the regexp via capturing parenthesis, but this would require pretty much completely pre-parsing the regexp to see whether it has capturing parenthesis (as opposed to non-capturing or other uses of the '(' and ')' characters).
@ksperling Thanks. Your solution will have to do for now.
@legomind Another idea to solve the same issue: Use $urlRouterProvider to do a redirect from e.g. '/{username}' to '/{username}/1' or whatever your default page is, then the state.url only needs to handle the case where the parameter is present.
+1 support
url: '/:username[/:page[/:question]]'
I'm sure I've seen that syntax in some router framework (can't remember).
+1 support as well
.state('user.add', {
url: '/add',
templateUrl: 'app/user/user.add.html',
controller: 'AddUserController'
})
I would like to pass few optional param with the url.
users/add?groupId=12&orgId=2
So a user can visit the users/add
directly or from another controller I can transition to user.add
state with those param values.
You can already do query params. @ksperling are query params optional?
I'm afraid it is not unless I'm doing something wrong. If I don't pass groupId
to url then it hits my otherwise route.
url: '/add/{groupId}'
But what if you do the URL like this? url: '/add?groupId'
Then navigate to either /add or /add?groupId=123
yes, query parameters are optional. Like @timkindberg shows in his example, you still have to declare them in the URL pattern though, so that $stateProviders knows which parameters you're interested in, i.e. your URL pattern should be something like
url: 'users/add?groupId&orgId'
Thanks, that worked! I did try it earlier but got exception from ui.router. I must have done something wrong.
+1 to add optional paramaters like item/{:id?}
+1
+1
Upvote :+1:
url: '/:username[/:page[/:question]]',
defaultParams: {page: 1}
+1 This should be top priority, not 0.4 milestone
One way to get around it, is to check first if the value given to the optional parameter is not the name of a child state.
If it is, then the URL should be treated like it points to the child state, skipping the optional parameter on the parent.
@stereokai Since it's obviously top priority for you, you're welcome to work on it and submit a patch.
I am already working on one, using the $stateProvider decorator :) I'll post it here when I'm done On Jan 1, 2014 2:10 AM, "Nate Abele" notifications@github.com wrote:
@stereokai https://github.com/stereokai Since it's obviously top priority for you, you're welcome to work on it and submit a patch.
— Reply to this email directly or view it on GitHubhttps://github.com/angular-ui/ui-router/issues/108#issuecomment-31415793 .
@nateabele @ksperling
A small update:
I have just spent 3 hours with the UI-Router code - which was a stimulating and intriguing journey. I have dug into the depths of $UrlRouterProvider
and I now understand the relationship between it and the UrlMatcher
s, as well as how UI-Router applies this relationship when handling location changes and state transitions. Pretty effing awesome code there, guys.
Okay, so as I mentioned above, one way I can see which makes optional parameters possible, is checking if the value of a parameter is in fact the URL segment of a child state. So, to give an example:
Parent state URL: /parent[/:optionalParam]
Child state URL: /child
In this example, if optionalParam
holds the value "child"
, it can't be captured and the transition should be delegated to the next rule, i.e. the child state.
So far what I did is attach the UrlMatcher
s to every rule, just so I can access them from within UrlMatcher.exec
.
I'm going with the syntax suggested by @xixixao above, so next I will be adding the parsing of those square brackets to the placeholder
regex. Regular expressions have never been my strong side, so for now, I won't be taking care of nested optional parameters.
To access the UrlMatcher
s from the exec
function, I also had to define the rules
array outside of $UrlRouterProvider
. It's only 1 closure jump, so it's not so bad. However, that strategy might still suck - I haven't yet thought that one out well enough, but executing this check on all child states might pose a significant impact on performance, as it could lead to loops over loops on the rules
array and the objects within. Perhaps building a hierarchy object, optimized for recursion, in the UrlMatcher
constructor's while
loop, is a better direction.
Another way to optimize is to set up a flag on rules which have optional parameters, so rules without them will completely skip on looking for clashes with state paths and spare some precious CPU cycles.
Okay, that's it so far. I'll update next week as I progress. Sorry if I don't make sense, I'm not a native English speaker
I like the syntax :) If you need any help, let me know.
@brian-frichette Thanks! I appreciate it. I'm picking up work from where I stopped this weekend, so I'll keep you posted :)
:+1:
+1
It would be nice if the optional flag was the same as angular-router (/required/:optional?/:anotherOptional?
), but as long as it works!
Any update on this issue?
+1 to any of those syntaxes.
/:required/:optional?/:anotherOptional?
and /:username[/:page[/:question]]
I think as a start it should be fairly easy to support /url/{optionalpar:regex}?/child
, because the regex avoids the problem of having to check whether the optional parameter might be a child.
e.g. https://gist.github.com/towr/e721aa022481b3ceae93
I suppose the (zend-like) /:username[/:page[/:question]]
syntax is a bit nicer, because you don't have to mess around with the previous/next segment to handle the //
issue for empty optional parameters. (And of course it gives more options, such only allowing an optional question if there is a page)
@diogobeda Was very occupied in the past month, and this task was pushed back, but according to my schedule I will focus on this towards the end of next week. That means Wednesday or so.
Rooting for you @stereokai. Viel Erfolg!
Danke Dustin!
Sorry for the big promises and even bigger delays! We had an unexpected breakthrough with an unexpected investor, and there was a lot of pressure with preparing an ocean of things for next week.
I will continue with this issue later today in the afternoon and will post my updates here as I go! Hold tight
I've got an update, it's working very well! I am adding annotations and will commit to my own fork (I don't have tests, also I couldn't think of a way to make the "unbalanced test group" check work with optionals, so that's definitely a breaking change).
Sweet, thanks @stereokai !
The syntax I used just for starters is url: '/:username/[page]/[question]'
- note that the slash is outside the brackets.
Subviews will work, i.e.: url: '/userprofile/[id]/photos/'
(haven't tested without trailing slash yet)
You can see the changes and get it at: https://github.com/stereokai/ui-router/commit/6723a21fd9c7b9fda25f7c7ad56f8120e1d70d08
Run grunt build
to get the compiled file.
I would like to hear your opinions regarding the parameter syntax.
I used [oppam]
because it made sense to me, it's familiar from practically everywhere in the programming-o-sphere, and I believed it's friendly to newcomers not familiar with the UI-Router syntax.
However, looking at it now, it breaks the current pattern, which in turn might cause even more confusion with newbies. Another downside comes up when considering nested optionals: /[oppam1/[oppam2/[oppam3]]]
or the even less consistent /[oppam1[oppam2[oppam3]]]
. Both would have to translate anyway to /oppam1/oppam2/oppam3
eventually.
So I'm thinking about changing the syntax to [/:oppam1]
as proposed above. Your feedback would be highly appreciated here!
I think I would prefer /literal1[/:oppam1][/literal2[/:oppam2]]
style, because it also allows you to denote which slashes and literals are optional. (And it's familiar to me from zend2)
+1 for @towr 's opinion
There was a missing line of code in my commit earlier, I fixed that now.
I find it odd to have the slash outside of the container, and I find nested optionals unnecessary because there's implicit hierarchy: /library[/section][/book][/chapter][/page][/line]
. It's pretty clear that there won't be chapter without book.
It's also kind of strange to have an optional where subsequent params can still be defined when it is not (in your example :userprofile/[id]/photos
). Photos can't operate without an id (and probably nothing else could either).
@jshado1 of course it can:
:userprofile
would take me to my own profile when I'm logged in, while :userprofile/[id]
would take me to my friend's profile. In the same manner, :userprofile/photos
would take me to my photos library and :userprofile/[id]/photos
to my friend's. Just to illustrate.
I do agree with your outlook on implicit hierarchy.
That's not RESTful because /userprofile/photos
for me is not the same for you.
Who said the URL structure needs to be RESTful? That's up to the implementers to decide.
I thought RESTful properties only apply to server-side APIs? I don't see how it has anything to do with client-side routing...
It would be great to hear from @ksperling and @nateabele on this.
Indeed, guys, give me your final feedback, and your thoughts on where to take it next - and I'll keep the commits pouring in :)
I do need a litte help with tests, though. I don't have any experience with writing them...
RESTful definitely applies to client-side, and it was the intention for Angular's original router.
I can help with tests. I'm somewhat new to them myself, but now I write about 2 per week.
RESTful is per application. IMHO ui-router should support RESTful, not necessarily enforce it.
Btw, can you nest optionals? :userprofile[/details[/id]]
Not yet - that's a whole other degree of complexity. To be honest I'm not planning on taking it to that level by myself. Just making sure my solution is robust and up to standard with this project, while hopefully resolving the requirements of the people in this thread. But not that one, no :)
@nateabele and I are too busy to help with this. There seem to be enough people in here that are interested, so get it where you want it amongst yourselves and submit a PR. Thanks for your efforts guys!
@stereokai fwiw my opinion is to do similar to what you have now but with slashes inside the brackets and no trailing slash (because we don't really recommend trailing slash, even though I know people want it).
@timkindberg Cheers. I will go with [/oppam]
, without nesting. Will be done with it this week. Somebody will have to take care of the tests though. Anybody cares to take responsibility? Worst case just tell me how to do it and I will try to push it into my schedule as well
I will try to pick up from where I stopped tomorrow. Will update here.
no need to differentiate from angular-router. let's use ?
syntax for optional params.
@joshrtay that's fine with me
I fiddled with some regex, but this is beyond me.
I need the last parameter in my state to be optional. In other words: capture it if it is there, but otherwise ignore it.
Something like: