0

I have a form that looks like:

<form action="search.php" method="post">
        <fieldset>
          <label for="level_one">Main category</label>
          <select name="level_one" id="level_one">
            <option value="0">All main categories</option>
                        <option value="7">Health</option>
                        <option value="11">Life</option>
                        <option value="8">Mind</option>
                        <option value="16">Relationships</option>
                      </select>
          <label for="level_two">Sub category</label>
          <select name="level_two" id="level_two">
            <option value="0" class="no_parent">All categories</option>
                        <option value="36" class="parent_id_7">Swine flu</option>
                        <option value="34" class="parent_id_7">Therapies</option>
                        <option value="40" class="parent_id_11">Bullying</option>
                        <option value="28" class="parent_id_11">Volunteering</option>
                        <option value="19" class="parent_id_8">Depression</option>
                        <option value="29" class="parent_id_16">Relationship problems</option>
                        <option value="37" class="parent_id_16">Separation and divorce</option>
                      </select>

          <input type="submit" value="Search" />
        </fieldset>
      </form>

With JQuery I hide the second select, then when the first select changes JQuery looks at the selection and shows the second select with only the relevant items in it. The JQuery:

$(document).ready(function () {
  $('#level_two').hide()
  $('#level_one').change(function(){
   var current = $(this).val();
   if(current == 0) {
     $('#level_two').hide()
   } else {
     $('#level_two option').not('.no_parent').hide()
     $('.parent_id_'+current).show();
     $('#level_two').val("no_parent");  //gert g's addition :)
     $('#level_two').show()
   }
  });
});

This works fine except for a small issue. If I select "Health" in select 1, select 2 shows "swine flu" and "Therapies", then I select "Therapies", now if I select life in select 1, select 2 shows the correct options except the default text in select 2 still says "Therapies" even though the therapies option is hidden.

Is there a way to refresh the text to stop this happening.

Regards

Luke

UPDATE: I have updated the code to working order thanks to @Gert G for the solution

UPDATE: The current solution only works in FireFox :(

UPDATE: I have used a slightly modified version of @Paolo Bergantino's solution that works for sure on chrome and FF, yet to finish testing all browsers.

jQuery.fn.filterOn = function(radio, values) {
        return this.each(function() {
          var select = this;
          var options = [];
          $(select).find('option').each(function() {
            options.push({value: $(this).val(), text: $(this).text()});
          });
          $('#level_two').data('options', options);
          $('#level_one').change(function() {
            var options = $(select).empty().data('options');
            var haystack = values[$(this).val()];
            if($(this).val()==0){
              $('#level_two').hide().siblings('label[for="level_two"]').hide();
            } else $('#level_two').show().siblings('label[for="level_two"]').show();
            $.each(options, function(i) {
              var option = options[i];
              if($.inArray(option.value, haystack) !== -1) {
                $(select).append(
                $('<option>').text(option.text).val(option.value)
              );
              }
            });
          });
        });
      };
      $(document).ready(function () {
        $('#level_two').hide().siblings('label[for="level_two"]').hide();
        $(function() {
          $('#level_two').filterOn('#level_one', {
                        '7': ["35","12","17","32","33","46","30","31","15","36","34"],
                        '11': ["40","25","27","41","22","26","44","28"],
                        '8': ["19","21","20"],
                        '16': ["29","37","23"],
                        '10': ["14","43","45","39"],
                      }); //note there are way more values in these arrays as I did not enter the full form that I am using above just a short example
        });
      });
Community
  • 1
  • 1
Luke
  • 3,333
  • 2
  • 28
  • 44
  • 2
    Classes can't start with numbers...you need to start with valid HTML before debugging anything else (give them a prefix!). Also I'm definitely sure IE won't support you hiding/showing options (disabling, yes), I'm not sure about other browsers...I've never attempted this. – Nick Craver Jun 30 '10 at 11:40
  • Are you sure the change event is working correctly when retreiving the value? I would recommend changing the "var current" assignment to select the selected option, like so: var current = $("option:selected", this).val(); And see if the problem still occurs. – dan richardson Jun 30 '10 at 11:42
  • 1
    @Nick you are correct. IE definitely does not support showing/hiding select options. – dan richardson Jun 30 '10 at 11:43
  • 1
    I'm with @Nick; I don't think this will work very well. I think you'd be better off using AJAX to simply get the correct contents for the second select based on the value of the first. Alternatively, you could keep all the data on the page in javascript variables and simply regenerate the contents from those when the first select is chosen. – tvanfosson Jun 30 '10 at 11:44
  • @Nick I have edited the code to have a prefix on the classes, still the same issue though. @Tvanfosson unfortunately AJAX is not an option as the server admin will not allow it due to graceful degradation. @Danrichardson the script is working, you should be able to try it with the above code, its just leaving the last value selected in the select box selected item part – Luke Jun 30 '10 at 11:50
  • Do you even know what "graceful degradation" means? You are saying that AJAX is a no no, but there you are trying to fix this with javascript... Interesting... – Gavrisimo Jun 30 '10 at 11:55
  • 1
    @GaVrA, if javascript is disabled the user will be able to see both selects and therefore can select any of the categorys and sub categories, if I use ajax to populate them and javascript is off then they will not be able to select any sub categories. The current way I have it does degrade gracefully as the functionality is still there. – Luke Jun 30 '10 at 12:00
  • Luke - I hope you heed @Nick's words and do some cross-browser testing. I tried your solution in IE7, IE8, Chrome, Safari, Opera and Firefox, and *only* Firefox worked. – user113716 Jun 30 '10 at 12:15
  • @Nick and Patrick, you are both very correct, it sucks that you are because now I have to rethink this. :) But thank you for pointing it out, would be far worse if I didnt know right :) – Luke Jun 30 '10 at 12:48
  • Luke - Consider @tvanfosson's solution in the comment above. Not the AJAX one, but the one where he suggests keeping all the data in javascript variables. @tvanfosson - Maybe you could add an answer based on your idea that the OP can accept? – user113716 Jun 30 '10 at 13:14
  • @Patrick I have updated the answer, I found another stackoverflow post that had a great response, see updated code above. – Luke Jun 30 '10 at 13:35
  • Luke - Glad you found a solution. You should place it as an answer below instead of in the question, then click the checkmark to confirm that it was your solution. Helps to keep things less confusing for future readers. :o) – user113716 Jun 30 '10 at 15:48

2 Answers2

2

-- New and improved version --

jQuery

<script type="text/javascript">
  $(document).ready(function() {
    var LevelTwoData=[];
    LevelTwoData["7"]= { "36":"Swine flu",
                         "34":"Therapies" };
    LevelTwoData["11"]={ "40":"Bullying",
                         "28":"Volunteering" };
    LevelTwoData["8"]= { "19":"Depression" };
    LevelTwoData["16"]={ "29":"Relationship problems",
                         "37":"Separation and divorce" };

    $("#level_one").change(function() {
      $('#level_two').val("0");  // Set "All categories" as the selected option
      $('#level_two option:not(:first)').remove();  // Remove all previous values

      var LevelOneVal=$("#level_one").val();  // Grab main category value

      if(LevelTwoData[LevelOneVal]!=undefined) {  // If the category has subcategories
        $.each(LevelTwoData[LevelOneVal],function(Value,Text) {  // Loop through the subcateries and add them as options
          $('#level_two').append(
            $('<option></option>').val(Value).html(Text)
          );
        });

        $('#level_two').show();
      } else {
        $('#level_two').hide();
      }
    });
  });
</script>

HTML

<form action="search.php" method="post">
  <fieldset>
    <label for="level_one">Main category</label>
    <select name="level_one" id="level_one">
      <option value="0">All main categories</option>
      <option value="7">Health</option>
      <option value="11">Life</option>
      <option value="8">Mind</option>
      <option value="16">Relationships</option>
    </select>
    <label for="level_two">Sub category</label>
    <select name="level_two" id="level_two">
      <option value="0">All categories</option>
    </select>

    <input type="submit" value="Search" />
  </fieldset>
</form>

-- Original (works as originally asked by Luke, but classes only works in Firefox) --

jQuery

<script type="text/javascript">
  $(document).ready(function () {
    $('#level_two').hide()
    $('#level_one').change(function(){
     var current = $(this).val();
     if(current == 0) {
       $('#level_two').hide()
     } else {
       $('#level_two option:not(.s0)').hide()
       $('#level_two').val("s0"); // Reset the option
       $('.s'+current).show();
       $('#level_two').show()
     }
    });
  });
</script>

HTML

<form action="search.php" method="post">
  <fieldset>
    <label for="level_one">Main category</label>
    <select name="level_one" id="level_one">
      <option value="0">All main categories</option>
      <option value="7">Health</option>
      <option value="11">Life</option>
      <option value="8">Mind</option>
      <option value="16">Relationships</option>
    </select>
    <label for="level_two">Sub category</label>
    <select name="level_two" id="level_two">
      <option value="0" class="s0">All categories</option>
      <option value="36" class="s7">Swine flu</option>
      <option value="34" class="s7">Therapies</option>
      <option value="40" class="s11">Bullying</option>
      <option value="28" class="s11">Volunteering</option>
      <option value="19" class="s8">Depression</option>
      <option value="29" class="s16">Relationship problems</option>
      <option value="37" class="s16">Separation and divorce</option>
    </select>

    <input type="submit" value="Search" />
  </fieldset>
</form>

Essentially you need to reset the option for the second upon the refresh of the first select.

Gert Grenander
  • 16,866
  • 6
  • 40
  • 43
0

Just thought, you are not reselecting an option when you change the first dropdown for the second time. So it may just be a simple "selected" problem.
Try something like this at the end of your change event;

$('#level_two option.parent_id_'+current+':first').attr("selected", "selected").siblings().removeAttr("selected");

or maybe this will do too;

$('#level_two option').removeAttr("selected");
dan richardson
  • 3,871
  • 4
  • 31
  • 38