Reputation: 421
I have three dropdowns. Suppose there is the combination of "M / Grey" but not "M / Red" in the name="id"
dropdown. If I select "M" in the first .variant
dropdown the "Red" option should not be shown in the second .variant
dropdown.
$(document).ready(function () {
$('.variant').change(function(){
var options = $(this).find('.variant').children(":selected").get().map(function(el) {
return el.value
}).join(" / ");
$('select[name="id"] option:contains(' + options + ')').prop('selected', true);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<form action="#" method="post">
<select class="variant">
<option value="S">S</option>
<option value="M">M</option>
<option value="L">L</option>
</select>
<select class="variant">
<option value="Grey">Grey</option>
<option value="Red">Red</option>
<option value="White">White</option>
</select>
<br>
<select name="id">
<option value="M / Grey">M / Grey</option>
<option value="L / Grey">L / Grey</option>
<option value="S / Red">S / Red</option>
<option value="L / Red">L / Red</option>
<option value="M / White">M / White</option>
<option value="L / White">L / White</option>
</select>
</form>
Upvotes: 0
Views: 465
Reputation: 5767
First: You should add to each select a placeholder like an empty option
. Otherwise you couldn't trigger the change
event if you select a preselected value (here S
and Grey
).
To update the other select.variant
you have to compare its values (combined with the chosen value) with the values of the select[name="id"]
.
You could achieve this with multiple solutions, for example data-attributes, the value strings or classes. I used classes for the following solution.
<option class="m grey" value="M / Grey">M / Grey</option>
So you can simply check if there is an option that has the questionable class.
if (!$('option').is('.' + val + '.' + color_val)) {...}
At the beginning of the change
handler you have to "reset" the options of the other select.variant
(remove all disabled attributes).
Working example:
$(document).ready(function() {
$('.variant').change(function() {
const val = this.value.toLowerCase();
const variant_type = this.className.replace('variant', '').trim();
$('.variant:not(.' + variant_type + ') option').attr('disabled', false);
$('.variant:not(.' + variant_type + ') option').each(function() {
const other_val = this.value.toLowerCase();
if (!$('option').is('.' + other_val + '.' + val)) {
this.disabled = true;
}
});
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<form action="#" method="post">
<select class="variant size">
<option></option>
<option value="S">S</option>
<option value="M">M</option>
<option value="L">L</option>
<option value="XL">XL</option>
</select>
<select class="variant color">
<option></option>
<option value="Grey">Grey</option>
<option value="Red">Red</option>
<option value="White">White</option>
</select>
<br>
<select name="id">
<option></option>
<option class="m grey" value="M / Grey">M / Grey</option>
<option class="l grey" value="L / Grey">L / Grey</option>
<option class="s red" value="S / Red">S / Red</option>
<option class="l red" value="L / Red">L / Red</option>
<option class="m white" value="M / White">M / White</option>
<option class="l white" value="L / White">L / White</option>
<option class="xl red" value="XL / Red">XL / Red</option>
</select>
</form>
If you want to use data-attributes you have to modify the function a slightly bit. The select.variant
get instead of an additional class a data-type
attribute. For example:
<select class="variant" data-type="size">
Combined example: (data-attributes and classes)
$(document).ready(function() {
$('.variant').change(function() {
const val = this.value.toLowerCase();
const variant_type = this.dataset.type;
$('.variant:not([data-type="' + variant_type + '"]) option').attr('disabled', false);
$('.variant:not([data-type="' + variant_type + '"]) option').each(function() {
const other_val = this.value.toLowerCase();
if (!$('option').is('.' + other_val + '.' + val)) {
this.disabled = true;
}
});
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<form action="#" method="post">
<select class="variant" data-type="size">
<option value="S">S</option>
<option value="M">M</option>
<option value="L">L</option>
<option value="XL">XL</option>
</select>
<select class="variant" data-type="color">
<option value="Grey">Grey</option>
<option value="Red">Red</option>
<option value="White">White</option>
</select>
<br>
<select name="id">
<option class="m grey" value="M / Grey">M / Grey</option>
<option class="l grey" value="L / Grey">L / Grey</option>
<option class="s red" value="S / Red">S / Red</option>
<option class="l red" value="L / Red">L / Red</option>
<option class="m white" value="M / White">M / White</option>
<option class="l white" value="L / White">L / White</option>
<option class="xl red" value="XL / Red">XL / Red</option>
</select>
</form>
For a solution with data-attributes
only the select[name="id"]
gets instead of two classes two data-attributes, one for each possible data-type
-value - in this example: data-size
and data-color
. For example:
<option data-size="S" data-color="Red" value="S / Red">S / Red</option>
To get the data-values you can use the dataset
keyword. To select an element you can use attribute-selectors. For example:
const variant_type = this.dataset.type;
$('.variant:not([data-type="' + variant_type + '"])')
With the data-type
from the select.variant
you could define which data-attribute of select[name="id"]
you want to select. For example:
$('[data-' + other_type + '="' + other_val + '"]')
Working example:
$(document).ready(function() {
$('.variant').change(function() {
const val = this.value;
const variant_type = this.dataset.type;
const other_type = $('.variant:not([data-type="' + variant_type + '"])')[0].dataset.type;
$('.variant:not([data-type="' + variant_type + '"]) option').attr('disabled', false);
$('.variant:not([data-type="' + variant_type + '"]) option').each(function() {
const other_val = this.value;
if (!$('option').is('[data-' + variant_type + '="' + val +
'"][data-' + other_type + '="' + other_val + '"]')) {
this.disabled = true;
}
});
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<form action="#" method="post">
<select class="variant" data-type="size">
<option></option>
<option value="S">S</option>
<option value="M">M</option>
<option value="L">L</option>
<option value="XL">XL</option>
</select>
<select class="variant" data-type="color">
<option></option>
<option value="Grey">Grey</option>
<option value="Red">Red</option>
<option value="White">White</option>
</select>
<br>
<select name="id">
<option></option>
<option data-size="M" data-color="Grey" value="M / Grey">M / Grey</option>
<option data-size="L" data-color="Grey" value="L / Grey">L / Grey</option>
<option data-size="S" data-color="Red" value="S / Red">S / Red</option>
<option data-size="L" data-color="Red" value="L / Red">L / Red</option>
<option data-size="M" data-color="White" value="M / White">M / White</option>
<option data-size="L" data-color="White" value="L / White">L / White</option>
<option data-size="XL" data-color="Red" value="XL / Red">XL / Red</option>
</select>
</form>
If you want to auto update the third select when both select.variant
are chosen you could define a data object. For example:
let selected = {};
With each call of the change
handler you would update the object with the data-type
and the value (add a new entry to the object or overwrite an existing one):
selected[variant_type] = val;
After that you would update the third select
(add the selected
attribute to the fitting option), but only if both select.variant
were chosen, which means that both got an entry in the data object:
if (selected[variant_type] && selected[other_type]) {...}
Working example:
$(document).ready(function() {
let selected = {};
$('.variant').change(function() {
const val = this.value;
const variant_type = this.dataset.type;
const other_type = $('.variant:not([data-type="' + variant_type + '"])')[0].dataset.type;
selected[variant_type] = val;
$('.variant:not([data-type="' + variant_type + '"]) option').attr('disabled', false);
$('.variant:not([data-type="' + variant_type + '"]) option').each(function() {
const other_val = this.value;
if (!$('option').is('[data-' + variant_type + '="' + val +
'"][data-' + other_type + '="' + other_val + '"]')) {
this.disabled = true;
}
});
if (selected[variant_type] && selected[other_type]) {
$('option[data-' + variant_type + '="' + selected[variant_type] +
'"][data-' + other_type + '="' + selected[other_type] + '"]'
)[0].selected = true;
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<form action="#" method="post">
<select class="variant" data-type="size">
<option></option>
<option value="S">S</option>
<option value="M">M</option>
<option value="L">L</option>
<option value="XL">XL</option>
</select>
<select class="variant" data-type="color">
<option></option>
<option value="Grey">Grey</option>
<option value="Red">Red</option>
<option value="White">White</option>
</select>
<br>
<select name="id">
<option></option>
<option data-size="M" data-color="Grey" value="M / Grey">M / Grey</option>
<option data-size="L" data-color="Grey" value="L / Grey">L / Grey</option>
<option data-size="S" data-color="Red" value="S / Red">S / Red</option>
<option data-size="L" data-color="Red" value="L / Red">L / Red</option>
<option data-size="M" data-color="White" value="M / White">M / White</option>
<option data-size="L" data-color="White" value="L / White">L / White</option>
<option data-size="XL" data-color="Red" value="XL / Red">XL / Red</option>
</select>
</form>
Upvotes: 1
Reputation: 1772
Had the same idea as @biberman but my code allows you to change your .variants
's second class to whatever you like - it could be <select class="variant size">
or <select class="variant variant1">
or whatever
$(document).ready(function () {
function gatherCombinations () {
var combos = $('select[name="id"] > option');
var result = [];
for (var i = 0; i < combos.length; i++) {
var comboVal = $(combos[i]).val();
var comboValArr = comboVal.split(" / ");
result.push(comboValArr);
}
return result;
}
function isExistingCombination (var1, var2) {
var combinations = gatherCombinations();
for (var i = 0; i < combinations.length; i++) {
var combo = combinations[i];
if (combo.indexOf(var1) >= 0 && combo.indexOf(var2) >= 0) {
return true;
}
}
return false;
}
$('.variant').on('change', function() {
var variantType = $(this).attr('data-var');
var variantVal = $(this).val();
var otherVariants = $('.variant:not(.' + variantType + ')');
var otherVariantsOptions = $('.variant:not(.' + variantType + ') > option');
otherVariantsOptions.show();
for (var i = 0; i < otherVariantsOptions.length; i++) {
var otherVariantOptionVal = $(otherVariantsOptions[i]).val();
if (isExistingCombination(variantVal, otherVariantOptionVal) == false) {
$(otherVariantsOptions[i]).hide();
}
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form action="#" method="post">
<select class="variant size" data-var="size">
<option value="S">S</option>
<option value="M">M</option>
<option value="L">L</option>
</select>
<select class="variant color" data-var="color">
<option value="Grey">Grey</option>
<option value="Red">Red</option>
<option value="White">White</option>
</select>
<br>
<select name="id">
<option value="M / Grey">M / Grey</option>
<option value="L / Grey">L / Grey</option>
<option value="S / Red">S / Red</option>
<option value="L / Red">L / Red</option>
<option value="M / White">M / White</option>
<option value="L / White">L / White</option>
</select>
</form>
Upvotes: 2