A not-uncommon scenario in a form is the case of City/State selectors. If the user chooses a state, it would be nice to let them choose the city without seeing cities from other states. This same principle can apply to many situations where the value of one selector is used to limit the selections available in another.
This kind of thing typically requires some fairly complex code because real-world forms applications tend to be complicated. Most of the time, if you need this kind of dynamic behavior in your form, you’re either going to code it yourself if you’ve got the skills or hire someone with the skills to do it.
A Simple Approach
What if all we needed was something simple like our first example?
There is a way to do this that doesn’t require a lot of code, as long as all the options can be present when the form is loaded, and there is a simple relationship between the two selectors. The basic idea is you have a “parent” selector and a “child” selector. The parent selector determines which options are available in the child selector…in our example the parent is the state selector and the child is the city selector.
Note: this tutorial won’t work for Chosen selectors, it is for regular dropdown selectors only.
Here is How That Gets Set Up
The way this works is the child selector’s options are divided into groups using “optgroups” that correspond to the selections in the parent selector. For example, if you’ve got 25 states, the city selector will have 25 optgroups that have labels that match the states. Each of those optgroups will contain the cities for that state. This way, we know that when a state is selected, we can use the value of that selection to find it’s corresponding group in the cities, and only show the members of that group: the cities in that state.
In Participants Database, the cities dropdown is set up with a values string like this (this is not the complete string, just enough to show how it is structured):
Alabama::optgroup, Birmingham, Montgomery, Mobile, Huntsville, Alaska::optgroup, Anchorage, Arizona::optgroup, Phoenix, Tucson, Mesa, Chandler, Gilbert, Glendale, Scottsdale, Tempe, Peoria, Surprise, Arkansas::optgroup, Little Rock, California::optgroup, Los Angeles, San Diego
And the “state” selector gets a values string like this:
Alabama::AL, Alaska::AK, American Samoa::AS, Arizona::AZ, Arkansas::AR, California::CA
Note: this code was updated on February 17, 2017 to allow the child’s value to be shown initially
And just so you can see it in action, here it is in a signup form template. You’ll notice that it is simply inserted at the top, after the PHP close tag and before the <div> tag. When the template is loaded the script goes into action, putting a handler on the parent field so that when a selection is made, the child selector will show the appropriate selections.
27 thoughts on “Dropdown Selectors: limit selections based on another selector”
I’m sure it’s something on my end, but does this not work with Tabs? I’ve updated my template, but the Tabs then the tabs function no longer works.
Forget the above. Rookie mistake. I wasn’t using the template from the Tabs plugin.
OK, thanks, glad you got it figured out.
I have two issues with this one.
1. If somebody is translating the page (example with chrome add-on) to a different language, the parent get a different value which makes sense but then nothing is shown in the child dropdown.
2. It doesn’t seem to work on safari browser, any thoughts?
This article is really only a tutorial to get you started, not meant to be a complete implementation…so yes, you will run into complications with things like in-browser translation that won’t be compatible, but there’s little you can do about that that isn’t tremendously complex.
About Safari…It’s working for me, so I don’t know what problem you’re running into there…you need to check the developer tools console to see what the specific issue is in that case.
Thanks a lot Roland.
To tackle issue #1, I decided to go to a translation plugin, and keep those in english.
For Safari, good to read it is supposed to work, I will look further on my side.
I got it to work by putting the code in the pdb-record-default.php
Changed Parent/child to Region/city
I works, but when saved the city disappears. When refreshed the city blinks and then remains empty
? what would cause this?
and how would I add more menus (not region or city) in the same file?
but what is making the city disappear from the field after saving?
It actually saves though
You’re using the signup form, it resets to the default after you save, that’s normal.
no, I added it to the pdb-record-default.php
I am 100% sure of that
After alot of research on similar state/city code, it seems there was an issue with how the Save button is formatted; it should not reload the page.
OK, I’m sorry I didn’t notice you were trying to use this in a different way. A save button on the record edit ([pdb_record] shortcode) does refresh the page, but the city value should get picked up from the record data. The JS is probably not set up to work with the record edit form because it’s clearing the values as soon as it’s loaded. It looks like you will need to alter the clear_child function so that it does not clear the value when it’s loaded.
Buenos Aries::ArgentinaBuenos Aries,
Is there a way to show the value in this format?
It is important for the UX on the frontend viewing
is seems to have taken away the html here too.
I would like the value to show on frontend:
Buenos Aries (below but not bold)
It’s not possible to include HMTL tags in the options a dropdown selector. This is a limitation in HTML, not the plugin.
I dont need the in the list itself, just what is shown on the frontend after selected.
I tried simply getting rid of the optgroup and added
Argentina Buenos Aires,
The list doesnt show the html & it shows the proper format on the frontend.
All good now:)
could someone post a live link that shows this in action?
I just cant put my head around it yet
This works well, thank you. However, when I have the same child options for multiple parent fields it wont show up at any of them accept the first one. I am creating a sign up sheet where people can select their master and based upon that their track. However some tracks, such as EE, fall under two masters Geoscience and Civil Engineering. I’ve entered it for both masters but it only shows up for one and is not an option for the other. how can I avoid this?
The “title” part of each option in a dropdown must be unique. This has nothing to do with the functionality described in this tutorial, it is generally true for all fields with options.
As you may know, each value in the dropdown (or any field that has options) can have two parts: a title and a value. If you need to have two of the same value in your dropdown, each one must have a different title. The title is the first term of each pair separated by a double colon…for example in my city dropdown I might have:
This allows the options to have two cities named Wailua. I know this is not optimal, it can appear redundant in a dropdown that uses optgroups, but for historical reasons, it has to be the title that is unique.
how to make the user receive his detailed form at the same time as the private link in the registration confirmation email
You need to set this up in the email template: you can include information from any value in their submission. The template is in the plugin settings under the “Signup Form” tab and is called the “Signup Response Email”
Could you please post a live example of how we would setup the state and city fields?
That’s possible, but it will take me a while to put that together.
Do you have a simple way to make a form field only being required if a specified selector box is selected?
E.g. Do you have a profile on XXX yes/no
If yes then enter your profilename here (new form field)
BTW I love the Participant Database which really makes it for me :D