Surge Pedroza Surge Pedroza - 1 month ago 7
Ruby Question

How do I retain the optgroup labels after filtering a multi select box?

I currently have a dropdown with Buildings that filters a Multi Select Box with various Rooms grouped by their respective Building.

Everything works great, except that when I filter the Multi Select Box via the dropdown, the Multi Select Box filters correctly, but removes the optgroup label that informs the user what Building the Rooms belong to.

EX: Lets say I select Accounting Library via my Dropdown

<optgroup label="Accounting Library">
<option value="143">105A</option>
<option value="144">105B</option>
</optgroup>
<optgroup label="Ahmanson Center">
<option value="721">fad</option>
<option value="737">zzz</option>
</optgroup>


I then get...

<option value="143">105A</option>
<option value="144">105B</option>


Which is correct, except that I'd like to keep the optgroup label for UI purposes.

Does anyone know how I can do this with my javascript?

JAVASCRIPT

$(function() {
var rooms = $('#key_room_ids').html();

$("#key_building_name").on("change",function() {
var building, options;
building = $('#key_building_name :selected').text();

options = $(rooms).filter("optgroup[label='" + building + "']").html();

if (options) {

###This doesn't return the values with the optgroup label
return $('#key_room_ids').html(options);

} else {
return $('#key_room_ids').empty();
}
});
});


FORM

<%= simple_form_for(@key, html: { 'data-parsley-validate' => '' }) do |f| %>

###Dropdown Filter
<%= f.collection_select :building_name, Building.order('name ASC'), :id, :name, {:include_blank => '- Please Select A Building To Filter The List Below -'}, { class: "form-control" } %>

###Multi Select Box Grouped by Building
<%= f.grouped_collection_select :room_ids, Building.order('name ASC'), :rooms, :name, :id, :name, {include_blank: "- Please Select The Rooms This Key Works For -"}, {multiple: true, size: 10, :class => "form-control"} %>

<% end %>

Answer

If I understand you correctly, you want to remove all of the optgroup elements (and their options) that do not match the selected building. That concept can be expressed pretty clearly with one line of jQuery code:

$('#key_room_ids').find("optgroup:not([label='" + building + "'])").remove();

In context:

$(function() {
  var originalRooms = $('#key_room_ids').html();
  
  $("#key_building_name").on("change",function() {
    $('#key_room_ids').html(originalRooms);

    if (this.value != "all") {
      var building = $('#key_building_name :selected').text();
      $('#key_room_ids').find("optgroup:not([label='" + building + "'])").remove();
    }
  }); 
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<select id="key_room_ids">
<optgroup label="Accounting Library">
  <option value="143">105A</option>
  <option value="144">105B</option>
</optgroup>
<optgroup label="Ahmanson Center">
  <option value="721">fad</option>
  <option value="737">zzz</option>
</optgroup>
</select>

<select id="key_building_name">
  <option value="all">Show all</option>
  <option>Accounting Library</option>
  <option>Ahmanson Center</option>
</select>

Comments