In a bespoke shopping cart, I pull from my database a list of options that a particular product has. The number of these options can vary by product.
I then turn that list of options into a JavaScript array.
An example with 3 options:
{"Small":{"Super":{"Pack":"parta","Case":"parte"},"Maxi":{"Pack":"partb","Case":"partf"}},"Large":{"Super":{"Pack":"partc","Case":"partg"}},"X Large":{"Maxi":{"Pack":"partd"}}}
Using the above, I would now like to generate an HTML select field, listing all the "first" options:
<select>
<option value="Small">Small</option>
<option value="Large">Large</option>
<option value="X Large">X Large</option>
</select>
Once the user has selected the first option, I then need another <select> box to then load with options that are available for their selection. So, if they selected "Small" from above, the new select box would be:
<select>
<option value="Super">Super</option>
<option value="Maxi">Maxi</option>
</select>
Finally, when they select from this list, a 3rd select box loads in the final options, along with the part numbers as values:
<select>
<option value="parta">Pack</option>
<option value="parte">Case</option>
</select>
The number of options can vary, from zero to 4. But, each time when options are available, I need to pull the part number based on the users selection. The part number doesn't necessarily need to be the value of the last select, it can be pushed to a new hidden variable.
I can achieve this using ajax, by making an ajax call every time a selection is chosen, but can it be done via JavaScript / jQuery, without having to make ajax calls, given that the array is on the page and available to use?
When you dynamically create the select element, also determine which "node" in your tree structure goes with that element, and use it to:
add a default "Please select..." option to the select element
populate the select element further with the real options
determine the deeper node when an option is selected (also when the initial selection is made when the element is created), and use it to create the next select element with the same function
This cascade stops when the deeper node does not exist (when "Please select..." is selected) or it happens to be a string and not an object.
Here is some code for inspiration:
let optionTree = {"Small":{"Super":{"Pack":"parta","Case":"parte"},"Maxi":{"Pack":"partb","Case":"partf"}},"Large":{"Super":{"Pack":"partc","Case":"partg"}},"X Large":{"Maxi":{"Pack":"partd"}}};
let container = document.querySelector("#container");
addSelector(optionTree);
function addSelector(node) {
let select = document.createElement("select");
// Start with the default option:
let option = document.createElement("option");
option.text = "Please select...";
select.add(option);
for (let key in node) { // Populate the select element
let option = document.createElement("option");
option.value = key;
option.text = key;
select.add(option);
}
container.appendChild(select); // Add it to the page
function change() {
// Remove select elements that come after the selection
while (select.nextElementSibling) {
select.nextElementSibling.remove();
}
let key = select.value;
if (node[key] && typeof node[key] !== "string") {
addSelector(node[key]); // Create the next select element(s)
}
}
// Call the above function whenever a selection is made
select.addEventListener("change", change);
change(); // ... and also call it now
}
<div id="container"></div>
Assuming you already have the three select elements in the DOM, you can populate the first select, and add a change event listener to both the first and second to achieve this. Try this
let $s1 = document.querySelector('#select-1');
let $s2 = document.querySelector('#select-2');
let $s3 = document.querySelector('#select-3');
let object = {"Small":{"Super":{"Pack":"parta","Case":"parte"},"Maxi":{"Pack":"partb","Case":"partf"}},"Large":{"Super":{"Pack":"partc","Case":"partg"}},"X Large":{"Maxi":{"Pack":"partd"}}};
// add options to first select
$s1.innerHTML = '<option></option>'; // empty select
Object.keys(object).forEach(val => $s1.append(new Option(val, val))); // append children
$s1.dispatchEvent(new Event('change')); // trigger change event
// listen to change event on first select/get options for second select
$s1.addEventListener('change', function(e){
$s2.innerHTML = '<option></option>'; // empty select
// append children
Object.keys(object[e.target.value] ?? []).forEach(val => {
$s2.appendChild(new Option(val, val));
});
// trigger change event
$s2.dispatchEvent(new Event('change'));
});
// listen to change event on second select/get options for third select
$s2.addEventListener('change', function(e){
$s3.innerHTML = '<option></option>'; // empty select
// append children
Object.entries(object[$s1.value]?.[e.target.value] ?? []).forEach(([key, val]) => {
$s3.appendChild(new Option(key, val));
});
});
select {min-width:80px}
<select id="select-1"></select>
<select id="select-2"></select>
<select id="select-3"></select>
Related
I am populating my dropdown menu dynamically and I sometimes end up with having a single element in the dropdown. For multiple elements, there is no problem, the onChange() of my select tag works perfect. However, when there is only 1 element, the onChange() does not invoke. How can I solve this problem? Thank you!
getOptions(){
var dynamicOptions = this.props.something
const returnedOptions = []
for(int i=0; i< dynamicOptions.length;i++){
returnedOptions.push(<option value = {dynamicOptions[i]}>something</option>
}
return dynamicOptions;
}
return(
<select onChange=this.onchangemethod, value = {something}>
{this.getOptions()}
</select>
)
You would be having the same problem if the user would like to select the first option of many, since it would be the already selected one and the user would not need to re-select it.
One workaround is to always specify an "empty" option with a placeholder text
<select onChange={this.onchangemethod}>
<option value="">Please choose an option</option>
{this.getOptions()}
</select>
This way, you will always have at least two options, and the user will have to open and select one.
An alternative is to pre-select the first option so that, again, in case of user inaction, there is one option selected.
for(int i=0; i < dynamicOptions.length; i++) {
const optionProperties = {value: dynamicOptions[i]};
if (i === 0) { optionProperties.selected: true };
returnedOptions.push(<option {...optionProperties}>something</option>);
}
I have a PHP page that creates multiple selects depending on how many the page before it gives it and creates the same number of options that there are selected (it's to choose the priority).
<select name="select1" id="idSelect" onchange="javascript:SelectOnChange();">
<option value="Select one">Select one</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
What I want to do is, whenever the user chooses an option that was already selected in another selection, to show an alert in order to let them know that their choice has already been taken and deny the change.
I want to compare the currently selected option to every previously selected option every time the user selects something from every select.
Basically your looking for a change event to loop through each select and notify duplicates.
$("select").change(function() {
var currentSelection = this.value;
$("select").each(function() {
if (this.value == currentSelection) {
alert("you've already chosen this!");
}
});
});
Something like this should work
Listen for change events
Get the element's seletedIndex
Grab all of the selects with getElementsByTagName()
Loop through and get the selected index
Compare to see if used
This could maybe work :
var $selects = $('select');
// WHen a select is changed.
$selects.onchange(function() {
// Storing it's selected value, assuming there is only one per select.
var value = $(this).selected().first().attr('value');
var $changedSelect = $(this);
// For each select...
$selects.each(function() {
var $otherSelect = $(this);
// ...that is not the one that just changed.
if( ! $otherSelect.is($changedSelect)) {
// If that other select's selected value is the same as the changed one's
if($otherSelect.selected().first().attr('value') === value) {
alert('...');
}
}
});
}
I didn't try it though, you might have to change a few details in it if it doesn't work.
I have 2 combo boxes. I want to display specific data in combo box 2 based on combobox 1 selection.
But I want to make it an ontime selection ... so when I press on the option I want from combobox 1 , combobox 2 is filled with data matching this selection.
I tried to put an on click function on combobox 1 options, but it didn't work when I click on them ...
So is there some method to do so ?
Assign the change event handler on the first dropdown, and then, based on the selected value, fetch the values that ought to be put in the second dropdown. Here's a typical manufacturer -> model example:
Markup:
<select id="manufacturers">
<option></option>
<option value="Audi">Audi</option>
<option value="Toyota">Toyota</option>
</select>
<select id="cars">
</select>
JavaScript:
var cars = {
Audi: [ 'A2', 'A3', 'A4' ],
Toyota: [ 'Auris', 'Avalon', 'Yaris' ]
};
$("#manufacturers").change(function () {
var $this = $(this);
var selectedValue = $this.val();
if (selectedValue) {
var $cars = $("#cars").empty();
var newCars = cars[selectedValue];
$.each(newCars, function () {
console.log(this);
$("<option>" + this + "</option>").appendTo($cars);
});
}
});
DEMO.
You should use the change (not click) event on the select tag itself (not on the option tag).
Example:
$('#combo1').change(function() {
// Load new content for #combo2 here
});
$('select.option1').change(function() {
// fill option2 with data from somewhere
});
Chained is simple jQuery plugin for chained selects
http://www.appelsiini.net/projects/chained
I've used this Plugin in some Projects and it works stable and as expected. Feel free to try it…
let's say I have a form that contains several "select" element that the User can choose.
when ready to submit, I need to find all the "select" that have changed.
how can I do it?
for example:
<form>
<input type="text" name="a"/>
<select name="b">...</select>
<select name="c">...</select>
<select name="d">...</select>
</form>
Using jQuery, something like this should work:
$('select').change(function() {
$(this).addClass('changed');
});
$('form').submit(function() {
var changed_selects = $('select.changed');
// do what you want with the changed selects
});
I would take advantage of the defaultSelected property on HTMLOptionElement instead of trying to keep track of selects that have changed:
form.onsubmit = function() {
var selects = form.getElementsByTagName("select")
, i
, changedSelects = []
, selected
, select;
/* Iterate over all selects in the form: */
for (i = 0; i < selects.length; i++) {
select = selects[i];
/* Get the currently selected <option> element: */
selected = select[select.selectedIndex];
/* Determine if the currently selected option is the one selected by default: */
if (!selected.defaultSelected) {
changedSelects.push(select);
}
}
alert(changedSelects.length);
}
You can iterate over all of the select elements on your form, determine if the selected option is the one that was selected by default, and push each one whose selected option wasn't the default into an array.
Example: http://jsfiddle.net/andrewwhitaker/abFr3/
You could register an event listener (using onchange, etc.) to determine if any changes were made.
Alternatively, you could keep a private copy of all of the previous values, then run a comparison before submit to check for changes.
Do something like:
var selectedVal = $("select[name='a'] option:selected").val();
//check this with your default selected val
You can attach the onchange event listener to each <select> element. When the event is triggered, you can store the actual elements in an a temporary array and reference it later when you are ready to submit. Note that the array can hold the actual DOM elements.
You need to clarify what you mean by "the select have changed".
If you mean have changed from their default value, then you should have one option on each select (usually the first) set as the default selected option. Then you can iterate over the selects and see if the option with the selected attribute (or where the defaultSelected property is true) is the selected option, e.g.
<script>
function anyChanged(){
var select, selects = document.getElementsByTagName('select');
for (var i=0, iLen=selects.length; i<iLen; i++) {
select = selects[i];
if (!select.options[select.selectedIndex].defaultSelected) {
// the selected option isn't the default
alert('select ' + (select.id || select.name) + ' changed');
}
}
}
</script>
<select name="one">
<option selected>one
<option>two
<option>three
</select>
<button onclick="anyChanged()">Check</button>
However, if you want to see if the user has changed the selected option based on some other logic, you need to say what it is.
if (document.myform.mycheckbox.checked)
If checkbox is checked, then do something...
...what line of code would do the same thing for a select box option?
if (document.myform.myselectbox.myselection.selected)
Is it something like that? I can't seem to find what it is I'm looking for.
What I'm doing is here:
Link to stuff nada workola
you are looking for:
if (document.myform.myselectbox.selectedIndex != -1)
When there is nothing selected the index returns -1.
If you actually want the internal value or text string for the selected option you can access it by index:
var selObj = document.myform.myselectbox;
var selIndex = selObj.selectedIndex;
var selOptionValue = selObj.options[selIndex].value;
var selOptionText = selObj.options[selIndex].text;
However you need to be aware that the behavior is also a bit dependent on how you have it displayed. With a "single" select element (e.g. a "drop down") if you don't specify that a particular option is "selected" then the first option (index 0) is considered to be selected as that is how it is visually displayed.
<select>
<option>red</option><!-- "selected" by default when rendered -->
<option>orange</option>
<option>yellow</option>
...
</select>
If you have a select element with a size attribute greater than 1 (e.g. 6) then visually there are none selected, thus the element will return -1 by default (if none were selected)
<select size="6">
<option>red</option><!-- NOT "selected" by default when rendered -->
<option>orange</option>
<option>yellow</option>
...
</select>
Either way, you can use code like this to determine what to do:
var mySelect = document.myform.myselectbox;
var selIndex = mySelect.selectedIndex;
if(selIndex != -1){
//an option is selected
if(selIndex == 0){
//first option is selected
} else if(selIndex == 1){
//second is selected
} else if(selIndex == 2){
//third is selected
}
} else {
//no option is selected
}
You could write this using a switch/case statement too, I've just expanded this to indicate a few values