Reputation: 44
I have 3 dropdowns where users are going to select their top 3 choices form a pre-defined list. I am trying to selectively remove the previously selected choice from in the subsequent dropdowns. That part seems to work, however the parent dropdown should still have all choices available.
What I am seeing is that all choices except the selected option are also removed from the first select and I can't figure out why.
I am guessing it has something to do with my limited experience with JS overall, and/or using $.push inside of a $.each but I can't figure out why.
$(document).ready(function() {
$('#Field1').on('change', function() {
var select1 = $(this).val();
const options1 = $(this).find('option');
var options2 = [];
var options3 = [];
console.log(select1);
console.log(options1);
options1.each(function(i, v) {
if (v.value != select1) {
options2.push(v);
}
});
$('#Field2').html(options2);
});
$('#Field2').on('change', function() {
var select2 = $(this).val();
var options2 = $(this).find('option');
var options3 = [];
console.log(select2);
console.log(options2);
options2.each(function(i, v) {
if (v.value != select2) {
options3.push(v);
}
});
$('#Field3').html(options3);
});
});
ul {
list-style-type: none
}
ul li {
margin: 25px auto;
}
label {
display: block;
margin-bottom: 12px;
}
select {
width: 320px;
padding: 6px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li attr="Drop_down" attrtype="select" name="q1" id="q1" class="form-q label-left form-focused"><label class="cf-label" for="Field1"><span><span>Drop-down</span></span><span class="screen-reader-legend">field type drop-down</span></label>
<div class="cf-field">
<select id="Field1" name="Field1" aria-labelledby="Field1" class="form-item-field cf-medium" vo="e" aria-invalid="false" data-parsley-id="11">
<option selected="True"></option>
<option value="choice 1" title="choice 1">choice 1</option>
<option value="choice 2" title="choice 2">choice 2</option>
<option value="choice 3" title="choice 3">choice 3</option>
</select>
</div>
</li>
<li attr="Drop_down_1" attrtype="select" name="q2" id="q2" class="form-q label-left"><label class="cf-label" for="Field2"><span><span>Drop-down</span></span><span class="screen-reader-legend">field type drop-down</span></label>
<div class="cf-field">
<select id="Field2" name="Field2" aria-labelledby="Field2" class="form-item-field cf-medium" vo="e" aria-invalid="false">
<option selected="True"></option>
<option value="choice 1" title="choice 1">choice 1</option>
<option value="choice 2" title="choice 2">choice 2</option>
<option value="choice 3" title="choice 3">choice 3</option>
</select>
</div>
</li>
<li attr="Drop_down_2" attrtype="select" name="q3" id="q3" class="form-q label-left"><label class="cf-label" for="Field3"><span><span>Drop-down</span></span><span class="screen-reader-legend">field type drop-down</span></label>
<div class="cf-field">
<select id="Field3" name="Field3" aria-labelledby="Field3" class="form-item-field cf-medium" vo="e" aria-invalid="false">
<option selected="True"></option>
<option value="choice 1" title="choice 1">choice 1</option>
<option value="choice 2" title="choice 2">choice 2</option>
<option value="choice 3" title="choice 3">choice 3</option>
</select>
</div>
</li>
</ul>
Upvotes: 0
Views: 82
Reputation: 5367
From a UX perspective, rather than removing the option from the select field you could also make it disabled. That way the user will know that it still is an option to change it.
Also you wouldn't have to mutate the entire select field when populating it with the new options. Just disable the option that was already chosen. This makes it scalable since you can add as many select fields as you wish.
The following code just loops over them all. And then disables the option the which is the same as the previously selected option from all select fields. This will enable you to choose the fields at random, so you wouldn't necessarily have to start at the first select field.
You could now also add options specific to a select field which are not affected.
$(document).ready(function() {
// only target select fields inside #select-wrapper
const selectFields = $('#select-wrapper').find('select');
selectFields.on('change', function(){
const thisSelect = $(this);
// for all other fields that the changed field
selectFields.not(thisSelect).each((i, selectField) => {
// loop through options
$(selectField).find('option').each((i, option) => {
// if option value is the same as selected option value disable it
if (option.value === thisSelect[0].value) {
$(option).prop('disabled', true);
}
// if there is an oldValue
if (thisSelect.attr('oldValue') && option.value === thisSelect.attr('oldValue')) {
// enable it again on each select option
$(option).prop('disabled', false);
}
});
});
// set the old value to make enabling it again possible
$(this).attr('oldValue', thisSelect.val());
});
});
ul {
list-style-type: none
}
ul li {
margin: 25px auto;
}
label {
display: block;
margin-bottom: 12px;
}
select {
width: 320px;
padding: 6px;
}
<ul id="select-wrapper">
<li attr="Drop_down" attrtype="select" name="q1" id="q1" class="form-q label-left form-focused"><label class="cf-label" for="Field1"><span><span>Drop-down</span></span><span class="screen-reader-legend">field type drop-down</span></label>
<div class="cf-field">
<select id="Field1" name="Field1" aria-labelledby="Field1" class="form-item-field cf-medium" vo="e" aria-invalid="false" data-parsley-id="11">
<option selected="True"></option>
<option value="choice 1" title="choice 1">choice 1</option>
<option value="choice 2" title="choice 2">choice 2</option>
<option value="choice 3" title="choice 3">choice 3</option>
</select>
</div>
</li>
<li attr="Drop_down_1" attrtype="select" name="q2" id="q2" class="form-q label-left"><label class="cf-label" for="Field2"><span><span>Drop-down</span></span><span class="screen-reader-legend">field type drop-down</span></label>
<div class="cf-field">
<select id="Field2" name="Field2" aria-labelledby="Field2" class="form-item-field cf-medium" vo="e" aria-invalid="false">
<option selected="True"></option>
<option value="choice 1" title="choice 1">choice 1</option>
<option value="choice 2" title="choice 2">choice 2</option>
<option value="choice 3" title="choice 3">choice 3</option>
</select>
</div>
</li>
<li attr="Drop_down_2" attrtype="select" name="q3" id="q3" class="form-q label-left"><label class="cf-label" for="Field3"><span><span>Drop-down</span></span><span class="screen-reader-legend">field type drop-down</span></label>
<div class="cf-field">
<select id="Field3" name="Field3" aria-labelledby="Field3" class="form-item-field cf-medium" vo="e" aria-invalid="false">
<option selected="True"></option>
<option value="choice 1" title="choice 1">choice 1</option>
<option value="choice 2" title="choice 2">choice 2</option>
<option value="choice 3" title="choice 3">choice 3</option>
</select>
</div>
</li>
</ul>
Upvotes: 1
Reputation: 5055
Like the comments have said, an issue you were having was moving the elements, rather than copying them. I've used jQuery's .clone()
to make a copy of the elements before moving them, so we can preserve the options in $('#Field1')
I've also added a function bound to the other selects $('select[id!="Field1"]')
that will make sure the placeholder text is removed when their value is updated.
$(document).ready(function () {
$('#Field1').on('change', function () {
// Change name to add readability
let value = $(this).val();
// Find the options with a value attribute that isn't the selected
let $option = $(this).find(`option[value!="${value}"]`).clone();
$('select').not(this).html($option);
});
$('#Field2').on('change', function () {
let value = $(this).val();
let $option = $(this).find(`option[value!="${value}"]`);
$('#Field3').html($option);
});
// Removing the other options from Fields2 + Fields3 once they're selected
$('select[id!="Field1"]').change(function () {
let value = $(this).val();
$(this).find(`option[value!="${value}"]`).hide();
});
});
ul {
list-style-type: none;
}
ul li {
margin: 25px auto;
}
label {
display: block;
margin-bottom: 12px;
}
select {
width: 320px;
padding: 6px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li attr="Drop_down" attrtype="select" name="q1" id="q1" class="form-q label-left form-focused"><label class="cf-label" for="Field1"><span><span>Drop-down</span></span><span class="screen-reader-legend">field type drop-down</span></label>
<div class="cf-field">
<select id="Field1" name="Field1" aria-labelledby="Field1" class="form-item-field cf-medium" vo="e" aria-invalid="false" data-parsley-id="11">
<option selected="True"></option>
<option value="choice 1" title="choice 1">choice 1</option>
<option value="choice 2" title="choice 2">choice 2</option>
<option value="choice 3" title="choice 3">choice 3</option>
</select>
</div>
</li>
<li attr="Drop_down_1" attrtype="select" name="q2" id="q2" class="form-q label-left"><label class="cf-label" for="Field2"><span><span>Drop-down</span></span><span class="screen-reader-legend">field type drop-down</span></label>
<div class="cf-field">
<select id="Field2" name="Field2" aria-labelledby="Field2" class="form-item-field cf-medium" vo="e" aria-invalid="false">
<option selected="True"></option>
<option value="choice 1" title="choice 1">choice 1</option>
<option value="choice 2" title="choice 2">choice 2</option>
<option value="choice 3" title="choice 3">choice 3</option>
</select>
</div>
</li>
<li attr="Drop_down_2" attrtype="select" name="q3" id="q3" class="form-q label-left"><label class="cf-label" for="Field3"><span><span>Drop-down</span></span><span class="screen-reader-legend">field type drop-down</span></label>
<div class="cf-field">
<select id="Field3" name="Field3" aria-labelledby="Field3" class="form-item-field cf-medium" vo="e" aria-invalid="false">
<option selected="True"></option>
<option value="choice 1" title="choice 1">choice 1</option>
<option value="choice 2" title="choice 2">choice 2</option>
<option value="choice 3" title="choice 3">choice 3</option>
</select>
</div>
</li>
</ul>
Upvotes: 2
Reputation: 13666
You can simplify your code quite a bit by not targeting each select individually.
$(document).ready(function(){
$('li:first-child select').on('change', function(){
// Clear previous selections
$('select').not(this).val('default');
// Get selected option
var selected = $(this).val();
// Enable subsequent select dropdowns
$('select').attr('disabled',false);
// Show all select options
$('select option').show();
// Hide option selected in first dropdown
$('select').not(this).find($('option[value="' + selected + '"]')).hide();
});
});
ul {
list-style-type:none
}
ul li {
margin: 25px auto;
}
label {
display:block;
margin-bottom:12px;
}
select {
width:320px;
padding:6px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li attr="Drop_down" attrtype="select" name="q1" id="q1" class="form-q label-left form-focused">
<label class="cf-label" for="Field1"><span><span>Drop-down</span></span><span class="screen-reader-legend">field type drop-down</span></label>
<div class="cf-field">
<select id="Field1" name="Field1" aria-labelledby="Field1" class="form-item-field cf-medium" vo="e" aria-invalid="false" data-parsley-id="11">
<option selected disabled>Make a selection</option>
<option value="choice 1" title="choice 1">choice 1</option>
<option value="choice 2" title="choice 2">choice 2</option>
<option value="choice 3" title="choice 3">choice 3</option>
</select>
</div>
</li>
<li attr="Drop_down_1" attrtype="select" name="q2" id="q2" class="form-q label-left">
<label class="cf-label" for="Field2"><span><span>Drop-down</span></span><span class="screen-reader-legend">field type drop-down</span></label>
<div class="cf-field">
<select id="Field2" name="Field2" aria-labelledby="Field2" class="form-item-field cf-medium" vo="e" aria-invalid="false" disabled>
<option value="default" selected disabled>Make a selection</option>
<option value="choice 1" title="choice 1">choice 1</option>
<option value="choice 2" title="choice 2">choice 2</option>
<option value="choice 3" title="choice 3">choice 3</option>
</select>
</div>
</li>
<li attr="Drop_down_2" attrtype="select" name="q3" id="q3" class="form-q label-left">
<label class="cf-label" for="Field3"><span><span>Drop-down</span></span><span class="screen-reader-legend">field type drop-down</span></label>
<div class="cf-field">
<select id="Field3" name="Field3" aria-labelledby="Field3" class="form-item-field cf-medium" vo="e" aria-invalid="false" disabled>
<option value="default" selected disabled>Make a selection</option>
<option value="choice 1" title="choice 1">choice 1</option>
<option value="choice 2" title="choice 2">choice 2</option>
<option value="choice 3" title="choice 3">choice 3</option>
</select>
</div>
</li>
</ul>
Upvotes: 1