0

I currently have 2 multiselect dropdowns on a page, one called 'hazards' and the other 'hp_codes'. They both populate their lists from a SQL DB and the idea is that 'hp_codes' will populate based on what is selected in 'hazards'.

So in theory someone could select hazard1, hazard2, and hazard3 and then the second list will churn out the options linked to those 3 hazards (some options may be the same - duplicates to be removed).

I'm a bit of a newby to this, hence throwing a net out, so I'd any suggestions are absolutely appreciated.

So far, I've tried the solution on this question(Bootstrap multiselect dynamic options based on first dropdown) to no avail (I typed all the options in to stop the page from pulling the hp_codes from the DB. Having the ability to keep these being pulled from the DB would be really helpful for updates in the future from a maintenance page point of view.

What would be the best way to achieve this?

Edit Here is a snippet of what currently sits in my form. To pull the data in to the multiselect from the DB

// Method to bind Dropdown
function fill_hazards_select_box($con)
{ 
 $output = '';
 $query=mysqli_query($con,"SELECT hazards FROM Chemilist_states");
    $cnt=1;
    while($row=mysqli_fetch_array($query))
    {
    $output .= "<option value='$row[0]'> $row[0] </option>";
    }

 return $output;
}

function fill_hp_codes_select_box($con)
{ 
 $output = '';
 $query=mysqli_query($con,"SELECT hp_codes FROM Chemilist_hazards");
    $cnt=1;
    while($row=mysqli_fetch_array($query))
    {
    $output .= "<option value='$row[0]'> $row[0] </option>";
    }

 return $output;
}

$month = date('m');
$day = date('d');
$year = date('Y');

$today = $year . '-' . $month . '-' . $day;
?>

Then to initialise the plugins

    <script>
        $(document).ready(function() {
            $('#hazards').multiselect({
                maxHeight: 300,
                buttonWidth: '505px',
                dropRight: true,
                nonSelectedText: 'Select Hazard Statement(s)',
                includeResetOption: true,
                includeResetDivider: true,              
                enableFiltering: true,
                includeFilterClearBtn: true,
                enableCaseInsensitiveFiltering: true,
            });
        });
    </script>

        <!-- Initialize the plugin: -->
    <script>
        $(document).ready(function() {
            $('#hp_codes').multiselect({
                maxHeight: 300,
                buttonWidth: '505px',
                dropRight: true,
                nonSelectedText: 'Select Hazard Properties',
                includeResetOption: true,
                includeResetDivider: true,              
                enableFiltering: true,
                includeFilterClearBtn: true,
                enableCaseInsensitiveFiltering: true,
            });
        });
    </script>   

and finally to put the mutliselect within the form

    <div class="form-group">
    <label>Hazard Statements: <span class="text-danger">*</span></label><br>

                                                                            <!-- Build your select: -->
    <select id="hazards" name="hazards[]"  class="form-control"  multiple="multiple" required>
    <?php echo fill_hazards_select_box($con);?> 
        </select>   
                                                                            </div>

                                                                        <div class="form-group">

    <label>Hazard Properties: <span class="text-danger">*</span></label><br>

                                                                            <!-- Build your select: -->
    <select id="hp_codes" name="hp_codes[]"  class="form-control"  multiple="multiple" required>
    <?php echo fill_hazards_select_box($con);?> 
    </select>   
                                                                            </div>
OT_Edge
  • 41
  • 1
  • 7
  • 1
    The best thing to start with is to divide this problem up in several sub-problems. 1. Showing a multi-select (solved?). 2. Getting the data of that back to the server (solved?). 3. Using that to select the "hp_codes" from your database. 4. Updating the second multi-select with those results. 5. Submitting the total. 6. Resolve any quirks. As you can see your question is broad. This is not good for getting useful answers. I think you should be more specific about the problem you want to solve now. – KIKO Software Dec 21 '21 at 22:43
  • Best bet to get help is to create a small snippet example and focus in on the exact question you have – Kinglish Dec 21 '21 at 22:45
  • @KIKOSoftware thanks for the reply. 1. I've got the multi-selects showing correctly with the correct options etc. 2. The data is reporting back to the server correctly and is also turning it from an array into string so that it reports back out the other end correctly when producing reports. 3. So I think this is where the sticking point is. The multiselects are currently pulling all the options in from the DB. But I've not found a way to filter the second list (hp_codes) based on what is selected in the first (hazards) which is what I'm trying to achieve. – OT_Edge Dec 21 '21 at 23:00
  • @Kinglish thanks - I've edited my original post to include the code I'm currently using for this. What I'm trying to do is make what appears in 'hp_codes' conditional on what is selected in 'hazards'. – OT_Edge Dec 21 '21 at 23:16
  • OK. I currently don't see any reporting back to the server of the hazards that have been selected. I see you use JQuery, I think it's therefore best to use the AJAX capability of that library. Make the multi-selects part of a form (which I think they are) and serialize them to your server using AJAX. There you can have a PHP script that analyzes them and returns a response. Based on that response you can restrict the options available. Again, this involves many steps, as you can see. Questions here have to focus on a single problem. Noone is going to explain all of this in any detail. – KIKO Software Dec 21 '21 at 23:19

1 Answers1

0

First you need a change handler on the initial select. Then you need to aggregate the selected options via a loop. Then you ship that input off to some ajax or other function to get the codes, which are then added into the other multi select. There are many ways to accomplish all these, here is one of them. I didn't see a jQuery tag on your post, so this is all vanillaJS, but easily transferred to jQuery if desired.

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('1')) results.push('AAA')
    if (hazards.includes('2')) results.push('BBB')
    if (hazards.includes('3')) results.push('CCC')

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

  })
})
<div class="form-group">
  <select id="hazards" name="hazards[]" class="form-control" multiple="multiple" required>
    <option value='1'>Oil slick</option>
    <option value='2'>Moose crossing</option>
    <option value='3'>Pothole</option>
  </select>
</div>

<div class="form-group">

  <label>Hazard Properties: <span class="text-danger">*</span></label><br>

  <!-- Build your select: -->
  <select id="hp_codes" name="hp_codes[]" class="form-control" multiple="multiple" required>

  </select>
Kinglish
  • 23,358
  • 3
  • 22
  • 43
  • thanks for the help with this, I've managed to get this working with a bootstrap multiselect for `hazards` and then just a regular multiselect for `hp_codes`. For some reason, when `hp_codes` is a bootstrap multiselect, it won't work, but it's not important as I can set the field to readonly and hide it. Is there a way to prevent this from displaying duplicates. Say option value 1 and 3 push AAA results but it would only be shown once? – OT_Edge Dec 24 '21 at 18:41
  • All good - I used `||` to get there and I don't see the duplication now with the longer code `if (hazards.includes('H270') || hazards.includes("H271") || hazards.includes("H272")) results.push('HP2')`. – OT_Edge Dec 24 '21 at 22:31