Skip to content

way to create optional parameter in url? #108

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

Closed
legomind opened this issue Apr 28, 2013 · 126 comments
Closed

way to create optional parameter in url? #108

legomind opened this issue Apr 28, 2013 · 126 comments
Labels
Milestone

Comments

@legomind
Copy link

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:

$stateProvider
.state \user.page, {
  url: '/:username/:page?'
  template-url: '...'
  controller: [
  \$stateParams
  ($stateParams) ->
    # The page parameter should be optional.
    # This should activate on both '/legomind/dashboard' as well as '/legomind'
  ]
}
@ksperling
Copy link
Contributor

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).

@legomind
Copy link
Author

legomind commented May 2, 2013

@ksperling Thanks. Your solution will have to do for now.

@legomind legomind closed this as completed May 2, 2013
@ksperling
Copy link
Contributor

@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.

@xixixao
Copy link

xixixao commented Jun 9, 2013

+1 support

  url: '/:username[/:page[/:question]]'

I'm sure I've seen that syntax in some router framework (can't remember).

@amitava82
Copy link

+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.

@timkindberg
Copy link
Contributor

You can already do query params. @ksperling are query params optional?

@amitava82
Copy link

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}'

@timkindberg
Copy link
Contributor

But what if you do the URL like this?
url: '/add?groupId'

Then navigate to either /add or /add?groupId=123

@ksperling
Copy link
Contributor

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'

@amitava82
Copy link

Thanks, that worked! I did try it earlier but got exception from ui.router. I must have done something wrong.

@benjamingeorge
Copy link

+1 to add optional paramaters like item/{:id?}

@tamtakoe
Copy link

+1

1 similar comment
@fakingfantastic
Copy link

+1

@miraage
Copy link

miraage commented Dec 21, 2013

Upvote 👍

url: '/:username[/:page[/:question]]',
defaultParams: {page: 1}

@timkindberg timkindberg reopened this Dec 22, 2013
@stereokai
Copy link

+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.

@nateabele
Copy link
Contributor

@stereokai Since it's obviously top priority for you, you're welcome to work on it and submit a patch.

@stereokai
Copy link

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" [email protected] 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//issues/108#issuecomment-31415793
.

@stereokai
Copy link

@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 UrlMatchers, 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 UrlMatchers 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 UrlMatchers 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

@bfricka
Copy link

bfricka commented Jan 14, 2014

I like the syntax :) If you need any help, let me know.

@stereokai
Copy link

@brian-frichette Thanks! I appreciate it. I'm picking up work from where I stopped this weekend, so I'll keep you posted :)

@bfricka
Copy link

bfricka commented Jan 16, 2014

👍

@JakobJingleheimer
Copy link
Contributor

+1

It would be nice if the optional flag was the same as angular-router (/required/:optional?/:anotherOptional?), but as long as it works!

@diogobeda
Copy link

Any update on this issue?

+1 to any of those syntaxes.
/:required/:optional?/:anotherOptional? and /:username[/:page[/:question]]

@towr
Copy link

towr commented Feb 13, 2014

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)

@stereokai
Copy link

@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.

@dustinrjo
Copy link

Rooting for you @stereokai. Viel Erfolg!

@RobbieTheWagner
Copy link

I'm a bit late to the party here, and sorry if I missed the answer to this somewhere, but is the trailing slash required? I have:

.state('predictions', {
        url: '/predictions/:id/:slug',
        templateUrl: 'views/predictions.html',
        controller: 'PredictionsCtrl'
      })

I can leave off my last param of slug, but I must still have the slash then. Is there a way to make that slash optional?

@adamreisnz
Copy link

I found this when running into the problem of double slashes. Making parameters optional using the method described in #1032 does NOT resolve this issue:

$stateProvider.state('tutorials.view', {
        reloadOnSearch: false,
        url:            '/:tutorialAlias/:lessonAlias/:lessonSlide',
        controller:     'TutorialsViewCtrl',
        templateUrl:    'tutorials/view/view.html',
        params: {
            lessonAlias: {value: null},
            lessonSlide: {value: null}
        }
    });

Then, when using ui-sref:

<a ui-sref="tutorials.view({tutorialAlias: tutorial.alias})">Start tutorial</a>

The link that gets created has a double trailing slash because of the missing lesson alias (e.g. some/url/tutorial-alias// ). Can't seem to find a way to fix this. Any thoughts? Using 0.2.13.

Edit: found a workaround by defining a mock-child state:

//State definition
    $stateProvider.state('tutorials.view', {
        url:            '/:tutorialAlias',
        controller:     'TutorialsViewCtrl',
        templateUrl:    'tutorials/view/view.html'
    })

    //With lesson
    .state('tutorials.view.lesson', {
        reloadOnSearch: false,
        url:            '/:lessonAlias/:lessonSlide',
        controller:     'TutorialsViewCtrl',
        templateUrl:    'tutorials/view/view.html'
    });

But I still think the url generator should be "clever" enough to strip out double slashes when parameters are missing.

@javifr
Copy link

javifr commented Dec 30, 2014

+1

1 similar comment
@niemyjski
Copy link

+1

@RobbieTheWagner
Copy link

+1 I need support for an optional trailing slash

@niemyjski
Copy link

Same here

@YidingW
Copy link

YidingW commented Jan 21, 2015

+1

@antecime
Copy link

Hey guys,

I just found the amazing squash parameter for the params optionnal object in ui-router.
At the bottom of this doc: https://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$stateProvider

So if we take the @AdamBuczynski example :

$stateProvider.state('tutorials.view', {
        reloadOnSearch: false,
        url:            '/:tutorialAlias/:lessonAlias/:lessonSlide',
        controller:     'TutorialsViewCtrl',
        templateUrl:    'tutorials/view/view.html',
        params: {
            lessonAlias: {value: null},
            lessonSlide: {value: null, squash: true} //The parameter's default value is omitted from the URL
        }
    });

So it will produce url like if we only have lessonAlias:
some/url/tutorial-alias/lesson-alias

Another exemple here with no lessonAlias and a custom lessonSlide value

$stateProvider.state('tutorials.view', {
        reloadOnSearch: false,
        url:            '/:tutorialAlias/:lessonAlias/:lessonSlide',
        controller:     'TutorialsViewCtrl',
        templateUrl:    'tutorials/view/view.html',
        params: {
            lessonAlias: {value: null, squash: true},
            lessonSlide: {value: null, squash: 'foo'} 
        }
    });

So it will produce url like:
some/url/tutorial-alias/foo

I think the squash param is a way to avoid double slashes when parameters are missing.

@RobbieTheWagner
Copy link

@juli3773 Thanks! I'll try that out tonight

@antecime
Copy link

@rwwagner90 tell me if it's working ^^

@JakobJingleheimer
Copy link
Contributor

For everyone 👍 this issue, this is already released—you don't need to vote for it anymore. I'm using it in one of my projects and it's working.

@JohannesFerner
Copy link

@jshado1 could you link the docs for this feature. I couldn't find it. Which one of the notations is implemented?

@RobbieTheWagner
Copy link

@juli3773 sorry for the late response, but it does work. Thanks!

@RobbieTheWagner
Copy link

So, now I have a new problem. How can I make a parameter required?

I have the following:

.state('profile', {
        url: '/profile/:id/:slug',
        templateUrl: 'views/profile.html',
        controller: 'ProfileCtrl',
        params: {
          slug: {value: null, squash: true}
        }
      })

I need /profile to not be valid though. I want only /profile/id to work

@antecime
Copy link

antecime commented Feb 5, 2015

What behavior do you want on /profile ?

@RobbieTheWagner
Copy link

@juli3773
/profile and /profile/ should both just not be valid. They should both be ignored and just go to a 404 page or whatever we decide to show when a route is not valid. Currently, without using squash: true if I go to /profile or /profile/ it ignores those because there is no id, but once I started using squash, it made /profile and /profile/ valid.

Essentially, what I could not do before was:
/profile/id without a trailing slash.

id is a required param and slug is not. I need the following to all be valid:

/profile/id

/profile/id/

/profile/id/slug

/profile/id/slug/

And these should be invalid:

/profile

/profile/

@muthu07
Copy link

muthu07 commented Feb 16, 2015

Hey guys, I am stuck on this dynamic parameter passing to my controller,
my html template:
ui-sref="/single/{{ item.id }}"

my state is look like this,
.state("single", {
url: "/single/:id",
controller: "single",
templateUrl: "partials/single.html"
})

controller:
.controller("single", ["ngCart", "$log", "$scope","$stateParams", function(a, b, c, d) {
c.id = d.id;
alert(c.id);
}])

But I am not getting proper output on this. Please any one give me solution..!!

@towr
Copy link

towr commented Feb 16, 2015

@muthu07
That ui-sref does not look valid. I think it should be ui-sref="single({id : item.id})"
A ui-sref should contain the (full) state name, not a url. If there are parent states, be sure to prepend them with periods.

NB, www.stackoverflow.com might be a better place for those kinds of questions, seeing as it does not seem to relate to this issue.

@jsancho
Copy link

jsancho commented Feb 18, 2015

@JohannesFerner as well as anyone else.
You can check the commit comments for some sort of interim documentation
#1032

Then there's the comments from the squash pull, where the syntax seems to have changed ever so slightly #1501

from params: { foo: { value: null } }
to params: { foo: null }

I managed to get it work with the new syntax.
The trickiest part for me is that the route with optional parameters is also the one for the main point of entry in the app, and I wasn't adding the opparam in the $urlRouterProvider.otherwise() clause.

Following the example above, that would be $urlRouterProvider.otherwise('/profile/:foo'); instead of $urlRouterProvider.otherwise('/profile');

It would be really neat if the official wiki could be updated - by someone in the know - with the current implementation as per the latest release 0.2.13

@jsancho
Copy link

jsancho commented Feb 18, 2015

Please disregard my previous comment, the documentation is here
http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$stateProvider
(just scroll to the params section at the bottom)

the params: { foo: null } format is a actually a shorthand when you only need to specify the value of the param.

And I just don't seem the get optional params to work as expected, which is also unrelated to the otherwise clause that

@ilbarzo
Copy link

ilbarzo commented Apr 13, 2015

+1

@nateabele
Copy link
Contributor

Alright, closing this out. @rwwagner90 if you have a different problem, please post that in a new issue so I don't have to read a small novel to figure the status of it. 😉 🍻

@rosinghal
Copy link

@juli3773 thanks a lot

@beeant
Copy link

beeant commented Oct 23, 2015

+1

@slavafomin
Copy link

I want to have optional integer-type parameter like this: url: '/sign-up/{partnerId:int}', is it possible?

@antecime
Copy link

antecime commented Dec 2, 2015

@slavafomin Yes it's possible! So you'll have:

url: '/sign-up/{partnerId:int}', 
params: { 
    partnerId: {value: null, squash: true}
}

@slavafomin
Copy link

Thank you @juli3773, I've finally managed to find a similar solution. Is squash: true is really necessary? I have the following code:

params: { 
    partnerId: null
}

And it seems to work great )

@antecime
Copy link

antecime commented Dec 7, 2015

@slavafomin the squash: true is necessary only if you want your parameter to be optional!

@danvass
Copy link

danvass commented Jul 4, 2016

I tried /s/{param1}/{param2}/{param3}and so forth including
params : { param1: {value : 'default'}, ... }

but it won't match /s/ and then auto populate the rest of the params with default value. It only works if I populate all params but the last one, then it will work but now show the default value in the URL. Any ideas on why @okendoken ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests