1

In my web application I have the following two select boxes:

<select id="project">
  <option value="">None</option>
  <option value="33">Some Project</option>
  <option value="32">Best project ever</option>
  <option value="31">Another project</option>
</select>

<select id="person">
  <option data-project_ids="[31, 33]" value="65">John</option>
  <option data-project_ids="[31]" value="66">Liz</option>
  <option data-project_ids="[]" value="67">Jim</option>
</select>

Using jQuery, how can I filter the #person options based on the value (= project_id) chosen in the #project select box?

If no project is chosen, then all persons should be displayed.

It might also happen that a project is pre-selected on page load.

j08691
  • 204,283
  • 31
  • 260
  • 272
Tintin81
  • 9,821
  • 20
  • 85
  • 178
  • @j08691 I fail to see how a "how can I do X" question would justify things being tried already. When you were little did you learn to tie your shoelaces by attacking them over and over again until it worked or did you do the sensible thing and get someone to show you how to do it? – Jamie Barker Jan 26 '15 at 14:37
  • 1
    @Tintin81 - It's always useful for us to see what you've tried, no matter how "n00bish" you feel your attempts were. At the very least it prevents us from duplicating what you've already tried. – j08691 Jan 26 '15 at 14:44
  • 1
    Questions don't necessarily need research to be asked; it helps inasfar as we don't try to give you a solution you've already tried; but that really only works for a certain class of questions (mostly debugging questions). Questions that ask how to do something in a given language do not necessarily need to show "What you've tried", but you could be downvoted if you don't (or if the question shows entitlement). None of that seems to be the case here. – George Stocker Jan 26 '15 at 17:35

1 Answers1

10

Option 1

Using indexOf: Working example

JS

function CheckProjects() {
    var curProject = $('#project').val(); //Get the current select project
    $('#person option').each(function () { //Loop through each option
        var arrProjects = $(this).attr('data-project_ids'); //Put the array of projects in a variable
        if (arrProjects.indexOf(curProject) > -1) { //If current project ID is in array of projects
            $(this).show(); //Show the option
        } else { // Else if current project ID is NOT in array of projects
            $(this).hide(); //hide the option
        }
    });
}

CheckProjects(); //Call the function when we run the page
$('#project').on('change', function() { //When we change the project, call the function
    CheckProjects();
});

Option 2

(Thanks to helpful comment by T.J.Crowder)

Using $.inArray: Working example

JS

function CheckProjects() {    
    var curProject = parseInt($('#project').val()); //Get the current select project and make it an integer
    $('#person option').each(function () { //Loop through each option
        var arrProjects = JSON.parse($(this).attr('data-project_ids')); //Put the array of projects in a variable
        if ($.inArray(curProject, arrProjects) > -1) { //If current project ID is in array of projects
            $(this).show(); //Show the option
        } else { // Else if current project ID is NOT in array of projects
            $(this).hide(); //hide the option
        }
    });
    //this is to stop the dropdown displaying a hidden option on project change
    if ($('#person :selected').is(':hidden')) { //If the selected person is now hidden
        $('#person').val(''); //Reset the person select box
    }
}

CheckProjects(); //Call the function when we run the page (at bottom of page, or within $(document).ready or something similar)
$('#project').on('change', function() { //When we change the project, call the function
    CheckProjects();
});
Jamie Barker
  • 8,145
  • 3
  • 29
  • 64
  • Thanks! The filtering doesn't work in my (Safari) browser, though. – Tintin81 Jan 26 '15 at 14:37
  • 1
    Does it work on another browser you have? Have a look at [this accepted answer](http://stackoverflow.com/a/1181586/2117156) for making indexOf work in older browsers. That might fix your problem :) – Jamie Barker Jan 26 '15 at 14:41
  • 1
    Re `var arrProjects = $(this).attr('data-project_ids'); //Put the array of projects in a variable`: `arrProjects` isn't an array, it's a string. The result of `attr` is **always** a string (or `undefined`, if you call it on an empty jQuery object). To make it an array, you'd have to parse it. Since the entries in the parsed array would be numbers, you'd also have to convert `curProject` (also a string, `val` is like `attr` in that regard) to a number because `Array#indexOf` uses `===` for comparison. – T.J. Crowder Jan 26 '15 at 15:53
  • @T.J.Crowder Ah of course, that would be why `$.inArray` didn't work when I tried it ^_^ – Jamie Barker Jan 26 '15 at 16:02
  • "Call the function when we run the page" is very questionable suggestion. Probably should be "call immediately when parsed, in real code don't do that and use `$(CheckProjects)` instead. (Also I'm puzzled why you added this comment to start with). – Alexei Levenkov Jan 26 '15 at 16:04
  • @AlexeiLevenkov I don't understand your comment. – Jamie Barker Jan 26 '15 at 16:09
  • 1
    (if you did not understand technical part of comment) - You assume that the script you've posted is *always* added at the end of the document. While indeed it there good reasons to do so not everyone does so. There are even cases when all scripts inculded/inlined in the head. In such cases script would fail as there is no DOM elements loaded yet. – Alexei Levenkov Jan 26 '15 at 16:17
  • (if you did not understand non-technical part about why to add comment) - Completely personal opinion here: comments on every line generally don't add value, especially if they can be expressed via code instead. I.e. in particular case you could have named function if such a way that it is clear what it does and when it should be called and avoid comment - indeed it is much harder but leads to cleaner code. Also comment like `.hide(); //hide the option` may be considered almost like insult as it assumes that reader is unable to look at the code. – Alexei Levenkov Jan 26 '15 at 16:22
  • @AlexeiLevenkov Got it. I'm just updating the code now anyway, but as for the `//hide the option` style comments, I put those in as pseudo code so you can just scan down the comments to see what is trying to be achieved. I take your point about "assumptions made" though – Jamie Barker Jan 26 '15 at 16:33
  • 4
    @Tintin81 Updated my answer with some more viable code – Jamie Barker Jan 26 '15 at 16:43
  • @JamieBarker: OK, thanks a lot for your help. It's still not working in the (latest) version of Safari but I will mark your answer as the correct one in the next few days unless someone comes up with an even better solution. – Tintin81 Jan 26 '15 at 19:17