0

I'm running a filter for my object on a django-run website. I have two select fields, with dropdowns based on related models to my model that i'd like to sort.

The problem is that some options are incompatible with each another and i'd like to hide the options of the second picklist based on what the user has selected on the first one.

I feel like i am going to use some JS but i've never used it before.

1st picklist: tasks <option value = task_id>
2nd picklist: crafts <option value = craft_id>

I have prepared a dictionnary that holds all the compatible values of any option selected on the first picklist, if that can help !

useful_dictionnary = {
    first_task_id = [list_of_compatible_craft_ids]
    ...
    last_task_id = [list_of_compatible_craft_ids]
}

How can i get JS to look at the task_id selected on the first picklist, and hide the options from the second picklist that are not in this list ?

Would be great! Thanks !

Here is my picklists code, if that helps

    <div class="form-group col-sm-4 col-md-3">
    <label for="id_tasks">Tasks:</label>
    <select class="form-control" id="id_tasks" name="task">
        <option value="">---------</option>
        <option value="1" selected="selected">Tie-job: Front-tie Marker</option>
        <option value="2">Tie-job: Scrapmachine support trackman</option>
        <option value="3">Tie-job: Plate Thrower</option>
        <option value="4">Tie-job: New-tie Marker</option>
    </select>
    </div>

    <div class="form-group col-sm-4 col-md-3">
    <label for="id_craft">Craft:</label>
        <select class="form-control" id="id_craft" name="craft">
        <option value="" selected="selected">---------</option>
        <option value="1">Senior Engineer</option>
        <option value="2">Roadmaster</option>
        <option value="3">Foreman</option>
        <option value="4">Assistant Foreman</option>
        <option value="5">Electrical Welder EA</option>
        <option value="6">Oxygen Welder OA</option>
        <option value="7">Railway Machine Operator (RMO)</option>
        <option value="8">Truck Driver (Type A, B or C)</option>
    </select>
    </div>
Malcoolm
  • 478
  • 2
  • 17
  • 1
    If you want more help, you will need to provide more specific code, but you will want to add a listener on the first select that fires on change and hide or show the options for your other select based on the value of the select. – Dylan Vander Berg Apr 14 '17 at 20:20
  • added the code for the picklists ! – Malcoolm Apr 14 '17 at 20:26

1 Answers1

1

This snippet should do the trick. Change compatibleIds to map the options for the second select based on the first one.

$(document).ready(function(){
  $("#id_craft option:not([value=0])").hide();
});


$("#id_tasks").change(function(){
  
  $("#id_craft").val("0");
  $("#id_craft option:not([value=0])").hide();
  var compIds = { 1: [ 1,2,3,4,5], 3 : [ 4,2,3,8,7], 4 : [ 7,9,1,5], 2 :[5,3,1,8]};
  for(var i = 0; i < compIds[$("#id_tasks").val()].length; i++){
    
    $("#id_craft option[value=" + compIds[$("#id_tasks").val()][i] + "]").show();
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="form-group col-sm-4 col-md-3">
    <label for="id_tasks">Tasks:</label>
    <select class="form-control" id="id_tasks" name="task">
        <option value="0" selected="selected">---------</option>
        <option value="1">Tie-job: Front-tie Marker</option>
        <option value="2">Tie-job: Scrapmachine support trackman</option>
        <option value="3">Tie-job: Plate Thrower</option>
        <option value="4">Tie-job: New-tie Marker</option>
    </select>
    </div>

    <div class="form-group col-sm-4 col-md-3">
    <label for="id_craft">Craft:</label>
        <select class="form-control" id="id_craft" name="craft">
        <option value="0" selected="selected">---------</option>
        <option value="1">Senior Engineer</option>
        <option value="2">Roadmaster</option>
        <option value="3">Foreman</option>
        <option value="4">Assistant Foreman</option>
        <option value="5">Electrical Welder EA</option>
        <option value="6">Oxygen Welder OA</option>
        <option value="7">Railway Machine Operator (RMO)</option>
        <option value="8">Truck Driver (Type A, B or C)</option>
    </select>
    </div>

Small add-on as the original question was about a django dictionary object: To use a django list or dictionnary in the javascript, it is pretty straightforward as the {{ django_variable }} works fine inside the script tags.

So the final JS for this django template page is:

$(document).ready(function(){
  $("#id_craft option:not([value=0])").hide();
});


$("#id_tasks").change(function(){

  $("#id_craft").val("0");
  $("#id_craft option:not([value=0])").hide();
  var compatibleIds = {{ my_python_dictionary }};
  for(var i = 0; i < compatibleIds[$("#id_tasks").val()].length; i++){

    $("#id_craft option[value=" + compatibleIds[$("#id_tasks").val()][i] + "]").show();
  }
});
Malcoolm
  • 478
  • 2
  • 17
Dylan Vander Berg
  • 1,809
  • 1
  • 22
  • 37
  • Thanks i'll try that in a sec; how can I use a python django variable (my useful_dictionnary ) as a javascript var (the compatibleIds) ? – Malcoolm Apr 14 '17 at 21:02
  • I'm not familiar with django, but maybe [this](http://stackoverflow.com/a/32824345/2297366) will be helpful. – Dylan Vander Berg Apr 14 '17 at 21:11
  • The compatibleIDs var that you used is not a dictionnary though, my ids for tasks are not necessarily in continuous order.. (some ids may be skipped); could you change the snippet for something that looks more like { 1: [ 1,2,3,4,5,], 3 : [ 4,2,9,8,7], 4 : [ 7,9,1,5] ... } ? Thanks ! – Malcoolm Apr 14 '17 at 21:28
  • ( making the dictionnary or list from django appear in the JS script in actually easy through {{ useful_dictionnary }}; – Malcoolm Apr 14 '17 at 21:34
  • 1
    Please be aware that SO is not a code writing service, so Dylan will be presenting his bank account later whahah. – yezzz Apr 14 '17 at 21:39
  • @yezzz haha true true ! I just don't know the first thing about JS syntax ! – Malcoolm Apr 14 '17 at 21:45
  • Thanks a lot for your help Dylan ! I'll try it out later tonight and accept your answer ! – Malcoolm Apr 14 '17 at 21:47
  • 1
    Dylan, I want gonna put in an answer, but seeing you labor I decided to just watch. Anyways, you might want to set selected to the first option, or trigger change on $.ready. Selecting the first option produces an error, so maybe return if there's no useful value. – yezzz Apr 14 '17 at 21:56
  • 1
    @Malcolm then be aware you need include jquery framework for this to work. – yezzz Apr 14 '17 at 21:56
  • I just made an edit. The code now changes the value of the selects on change so that there are no hidden options selected. Make sure you add in server side validation because there is nothing stopping anyone from going into the element and showing options. – Dylan Vander Berg Apr 14 '17 at 23:31
  • Thanks ! (No worries about server side validation, worst case the result of the query is just empty!). Any smart ideas about implementing something similar to three or for pick lists ? Or to contribute to the Django-filter addon adding this snippet ? – Malcoolm Apr 14 '17 at 23:33
  • You would just need to implement my concept, just with more. You would want to have a different object for each added level and choose the options for the next level based on the object like I did in my snippet. – Dylan Vander Berg Apr 14 '17 at 23:41
  • oh no @DylanVanderBerg ! It looks like this JS fix - that works fine on desktop - does not load on mobile (all options are still available..) any ideas ? thanks ! – Malcoolm Apr 19 '17 at 18:36
  • I would putting a `alert ("test")` in the change callback function. If that doesn't fire on mobile, we know that the problem is with the callback not firing. I would try a few different browsers. If on android, sometimes the stock browser has weird bugs. Try it on chrome and see if the alert works and if it changes properly. – Dylan Vander Berg Apr 19 '17 at 18:49