Tintin81
Tintin81

Reputation: 10207

How to filter / clone select box options with jQuery?

I have the following two select boxes:

<select id="project">
  <option data-person_ids="[75,76,77]">None</option>
  <option data-person_ids="[77]">Project A</option>
  <option data-person_ids="[75,76]">Project B</option>
  <option data-person_ids="[75]">Project C</option>
</select>

<select id="person">
  <option value="75">Person A</option>
  <option value="76">Person B</option>
  <option value="77">Person C</option>
</select>

How can I filter the #person options based on the value selected in #project?

This is a jQuery code snippet that a colleague came up with but I was unable to get it working because I am still new to jQuery:

$(function() {

  var $person = $('#person');

  $allPersonOptions = $person.children();

  $('#project').on('change', function() {
    var selected_project = $('#project').data('person_ids');
    filterOptions($allPersonOptions.clone(), +selected_project).appendTo($person.empty());
  });

});

function filterOptions($options, id) {
  return $options.filter(function() {
    return $.inArray(id, $(this).data('project_ids')) > -1
  });
}

Thanks for any help in this matter.

Upvotes: 0

Views: 484

Answers (2)

epascarello
epascarello

Reputation: 207501

Well your colleague gave you bad code.

First

var selected_project = $('#project').data('person_ids');

will return undefined since it is not on the select, it is on the option. It does not magically get the selected option's data attribute

var selected_project = $('#project option:selected').data('person_ids');

Next there is a random + in the code

filterOptions($allPersonOptions.clone(), +selected_project).appendTo($person.empty());
                                        ^^^

That is going to do a conversion, bad.

Next the filter code is looking for a data attribute

return $.inArray(id, $(this).data('project_ids')) > -1

There is no data attribute on that select's options. And the arguments are switched.

$(function() {

  var $person = $('#person');

  $allPersonOptions = $person.children();

  $('#project').on('change', function() {
    var selected_project = $('#project option:selected').data('person_ids');
    filterOptions($allPersonOptions.clone(), selected_project).appendTo($person.empty());
  });

});

function filterOptions($options, id) {
  return $options.filter(function() {
    return $.inArray(parseInt(this.value,10), id) > -1
  });
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<select id="project">
  <option data-person_ids="[75,76,77]">None</option>
  <option data-person_ids="[77]">Project A</option>
  <option data-person_ids="[75,76]">Project B</option>
  <option data-person_ids="[75]">Project C</option>
</select>

<select id="person">
  <option value="75">Person A</option>
  <option value="76">Person B</option>
  <option value="77">Person C</option>
</select>

Upvotes: 2

Sigismundus
Sigismundus

Reputation: 625

I have a version that reuses allPersonOptions (no need to clone) and only copies applicable options.

$(function() {
  var $person = $('#person');
  $allPersonOptions = $person.children();
    
  $('#project').on('change', function() {
    var ids = $('#project option:selected').data('person_ids');
    $person.empty();
    $allPersonOptions.each( function() {
      var id = parseInt($(this).attr('value'));
      if ($.inArray(id, ids) != -1 )
        $person.append(this);
    })
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<select id="project">
  <option data-person_ids="[75,76,77]">None</option>
  <option data-person_ids="[77]">Project A</option>
  <option data-person_ids="[75,76]">Project B</option>
  <option data-person_ids="[75]">Project C</option>
</select>

<select id="person">
  <option value="75">Person A</option>
  <option value="76">Person B</option>
  <option value="77">Person C</option>
</select>

Upvotes: 1

Related Questions