Home > Blockchain >  Select2 multiselect options to display options in another multiselect
Select2 multiselect options to display options in another multiselect

Time:01-31

I have just switched one of my multiselects to select2 as my previous checkbox multiselect was incompatible with my new page template CSS and looked very out of place.

What is meant to happen is in the first multiselect (now select2), users can select their plethora of options and a second multiselect below would populate with the relevant options that are tied to the first already selected and the field read only. This worked fine previously but is no longer doing so.

This is the code I'm using. The options for hazards in the select2 are pulled from a DB which is working as intended.

$(document).ready(function() {
    $('#hazards').select2();
});

window.addEventListener('DOMContentLoaded', () => {
  let hprops = document.querySelector('#hp_codes')
  document.querySelector('#hazards').addEventListener('change', e => {
    let options = e.target.options;
    let hazards = [];
    for (var i = 0, l = options.length; i < l; i  ) {
      if (options[i].selected) {
        hazards.push(options[i].value);
      }
    }

    hprops.innerHTML = '';
    hprops.setAttribute('disabled', true); // disable until we get the data in there
    // ajax to get actual data ...
    let results = []
    if (hazards.includes("H200") || hazards.includes("H201")) results.push('HP1')
    if (hazards.includes('H300') || hazards.includes("H301")) results.push('HP6')
    if (hazards.includes('H400') || hazards.includes("H410")) results.push('HP14')

    results.forEach(r => hprops.innerHTML  = `<option selected value='${r}'>${r}</option?`)
    hprops.removeAttribute('disabled');

  })
})

// array_unique compressed:
    function array_unique(d){var c="",b={},e="";var a=function(h,g){var f="";for(f in g){if(g.hasOwnProperty(f)){if((g[f] "")===(h "")){return f}}}return false};for(c in d){if(d.hasOwnProperty(c)){e=d[c];if(false===a(e,b)){b[c]=e}}}return b}


var optionValues = [];
$('#hp_codes').each(function() {
  optionValues.push($(this).val());
  $(this).remove(); // remove the option element
});

var cleanedArray = array_unique(optionValues); // clean the array

// let's go to paint the new options
for(var i in cleanedArray) {
  var opt = $('<option/>')
                .attr('value', cleanedArray[i]) // note that the value is equal than the text
                .text(cleanedArray[i]);
  $('#hp_codes').append(opt);
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/select2.min.js"></script>

          <div >
            <div >
              <label >Hazard Statements: </label>
              <span >*</span> </div>
            <div >
              <select  data-toggle="select2" id="hazards" name="hazards" multiple required>           
              <option value="H200">H200</option>
              <option value="H201">H201</option>              
              <option value="H300">H300</option>
              <option value="H301">H301</option>              
              <option value="H400">H400</option>
              <option value="H410">H410</option>              
              </select>             
            </div>
          </div>
          </br>
          <div >
            <div >
              <label >HP Codes: </label>
            </div>
            <div >
              <select  name="hp_codes" id="hp_codes" multiple readonly>
              </select>
            </div>
          </div>

When I debug this in the browser, it's currently showing that $ on this line $('#hp_codes').each(function() { is undefined. I'm unsure how to resolve this as it was working fine previously.

Edit: This is how it should work without JQuery

window.addEventListener('DOMContentLoaded', () => {
  let hprops = document.querySelector('#hp_codes')
  document.querySelector('#hazards').addEventListener('change', e => {
    let options = e.target.options;
    let hazards = [];
    for (var i = 0, l = options.length; i < l; i  ) {
      if (options[i].selected) {
        hazards.push(options[i].value);
      }
    }

    hprops.innerHTML = '';
    hprops.setAttribute('disabled', true); // disable until we get the data in there
    // ajax to get actual data ...
    let results = []
    if (hazards.includes("H200") || hazards.includes("H201")) results.push('HP1')
    if (hazards.includes('H300') || hazards.includes("H301")) results.push('HP6')
    if (hazards.includes('H400') || hazards.includes("H410")) results.push('HP14')

    results.forEach(r => hprops.innerHTML  = `<option selected value='${r}'>${r}</option?`)
    hprops.removeAttribute('disabled');

  })
})

// array_unique compressed:
    function array_unique(d){var c="",b={},e="";var a=function(h,g){var f="";for(f in g){if(g.hasOwnProperty(f)){if((g[f] "")===(h "")){return f}}}return false};for(c in d){if(d.hasOwnProperty(c)){e=d[c];if(false===a(e,b)){b[c]=e}}}return b}


var optionValues = [];
$('#hp_codes').each(function() {
  optionValues.push($(this).val());
  $(this).remove(); // remove the option element
});

var cleanedArray = array_unique(optionValues); // clean the array

// let's go to paint the new options
for(var i in cleanedArray) {
  var opt = $('<option/>')
                .attr('value', cleanedArray[i]) // note that the value is equal than the text
                .text(cleanedArray[i]);
  $('#hp_codes').append(opt);
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>

          <div >
            <div >
              <label >Hazard Statements: </label>
              <span >*</span> </div>
            <div >
              <select  id="hazards" name="hazards" multiple required>           
              <option value="H200">H200</option>
              <option value="H201">H201</option>              
              <option value="H300">H300</option>
              <option value="H301">H301</option>              
              <option value="H400">H400</option>
              <option value="H410">H410</option>              
              </select>             
            </div>
          </div>
          </br>
          <div >
            <div >
              <label >HP Codes: </label>
            </div>
            <div >
              <select  name="hp_codes" id="hp_codes" multiple readonly>
              </select>
            </div>
          </div>

CodePudding user response:

Simplified your code and placed the core logic to trigger the change. This will automatically react to any selection or removal from hazard options.

<html>
    <head>
        <title>Expense Tracker</title>

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/select2.min.js"></script>
<script>
$(document).ready(function() {
    $('#hazards').select2();

$('#hazards').on('change', function(){

  console.log($(this).val());

  $('#hp_codes').html('');

     $($(this).val()).each(function(i, node){

         //node is the value selected from Hazards

         //do the db call here.. I have just used 1 value, but this can be array of values resulted from DB

          var opt = $('<option/>')
                .attr('value', node ' - DB options') // note that the value is equal than the text
                .text(node ' - DB options');
          $('#hp_codes').append(opt);

     });

   });
});


</script>
    </head>
    <body>
    

          <div >
            <div >
              <label >Hazard Statements: </label>
              <span >*</span> </div>
            <div >
              <select  data-toggle="select2" id="hazards" name="hazards" multiple required>           
              <option value="H200">H200</option>
              <option value="H201">H201</option>              
              <option value="H300">H300</option>
              <option value="H301">H301</option>              
              <option value="H400">H400</option>
              <option value="H410">H410</option>              
              </select>             
            </div>
          </div>
          </br>
          <div >
            <div >
              <label >HP Codes: </label>
            </div>
            <div >
              <select  name="hp_codes" id="hp_codes" multiple readonly>
              </select>
            </div>
          </div>
</body>

</html>

CodePudding user response:

Keeping closer to your original code, I believe this is what is needed? The addEventListener was not firing for some reason for #hazards, so I used $('#hazards').on('change', ... instead.

Also, it seems as if all the code after the DOMContentLoaded handler is not used?
I added a alternative unique function to filter an array, commented-out.

//    $(document).ready(function() {
//        $('#hazards').select2();
//    });

window.addEventListener('DOMContentLoaded', () => {
    $('#hazards').select2();
  let hprops = document.getElementById('hp_codes')
//      document.querySelector('#hazards').addEventListener('change', e => {
// The hazards addEventListener was not firing?
  $('#hazards').on('change', e => {
    let options = e.target.options;
    let hazards = [];
    for (var i = 0, l = options.length; i < l; i  ) {
      if (options[i].selected) {
        hazards.push(options[i].value);
      }
    }

    hprops.innerHTML = '';
    hprops.setAttribute('disabled', true); // disable until we get the data in there
    // ajax to get actual data ...
    let results = []
    if (hazards.includes("H200") || hazards.includes("H201")) results.push('HP1')
    if (hazards.includes('H300') || hazards.includes("H301")) results.push('HP6')
    if (hazards.includes('H400') || hazards.includes("H410")) results.push('HP14')

    results.forEach(r => hprops.innerHTML  = `<option selected value="${r}">${r}</option>`)
    hprops.removeAttribute('disabled');
  })
})

// array_unique compressed:
function array_unique(d){var c="",b={},e="";var a=function(h,g){var f="";for(f in g){if(g.hasOwnProperty(f)){if((g[f] "")===(h "")){return f}}}return false};for(c in d){if(d.hasOwnProperty(c)){e=d[c];if(false===a(e,b)){b[c]=e}}}return b}
/* // an alternative unique
function onlyUnique(value, index, self) {
    return self.indexOf(value) === index;
}
*/
var optionValues = [];
//    $('#hp_codes').each(function() { // this removed the select!
$('#hp_codes').children().each(function() {
  optionValues.push($(this).val());
  $(this).remove(); // remove the option element
});

var cleanedArray = array_unique(optionValues); // clean the array
//    var cleanedArray = optionValues.filter(onlyUnique); // clean the array

// let's go to paint the new options
for(var i in cleanedArray) {
  var opt = $('<option/>')
                .prop('value', cleanedArray[i]) // note that the value is equal than the text
                .text(cleanedArray[i]);
  $('#hp_codes').append(opt);
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/select2.min.js"></script>

          <div >
            <div >
              <label >Hazard Statements: </label>
              <span >*</span> </div>
            <div >
              <select  data-toggle="select2" id="hazards" name="hazards" multiple required>           
              <option value="H200">H200</option>
              <option value="H201">H201</option>              
              <option value="H300">H300</option>
              <option value="H301">H301</option>              
              <option value="H400">H400</option>
              <option value="H410">H410</option>              
              </select>             
            </div>
          </div>
          </br>
          <div >
            <div >
              <label >HP Codes: </label>
            </div>
            <div >
              <select  name="hp_codes" id="hp_codes" multiple readonly>
              </select>
            </div>
          </div>

  •  Tags:  
  • Related