2

Hello everyone I need some help making a drop down menu that is reactive to classes contained in a set of options. What I want to do is have users select brochures (I'll call the brochure menu) and based on the classes contained in those options, a second drop down menu is populated based on the classes in the first.

For example selecting this option:

<option id="parRight" class="eng kor esp">Special Ed. Parents Rights</option>

Would create a second drop down I'll call the language selection drop down menu based on the classes above of "English" "Korean" and "Spanish" respectively and only those languages represented in the classes of that particular option.

So far I have been able to populate the list correctly only on the first try. My problem is that when I move on and select another brochure from the first menu my .append method is just adding to the first language selection drop down menu.

Here is the relevant code:

HTML

       <select id="docs">
            <option>- Choose a document to preview -</option>
            <option id="specEd" class="eng kor viet esp chin">Special Education Programs</option>
            <option id="parRight" class="eng kor esp">Special Ed. Parents Rights</option>
            <option id="cac" class="eng esp">CAC Brochure</option>
        </select>

        <div id="langs">
            <ul style="display:none;">
                <li>-Select a Language-</li>
                <li class="eng">English</li>
                <li class="esp">Español</li>
                <li class="kor">한국어</li>
                <li class="viet">Tiếng Việt</li>
                <li class="chin">中文</li>
            </ul>
        </div>

jQuery

    var $select = $("<select></select>");
    $("#langs").append($select);


    function englishTest(lang) {
    return lang.hasClass("eng");
    }

    function spanishTest(lang) {
    return lang.hasClass("esp");
    }

    function koreanTest(lang) {
    return lang.hasClass("kor");
    }

    function chineseTest(lang) {
    return lang.hasClass("chin");
    }

    function vietnameseTest(lang) {
    return lang.hasClass("viet");
    }

$("#docs").change(function(){
    console.log("test");
    var $selection = $("#docs option:selected");


    if (englishTest($selection) === true) {
            console.log("english passing");
            $select.append("<option>English</option>");
    } 
    if (spanishTest($selection) === true) {
            console.log("spanish passing");
            $select.append("<option>Español</option>")
    }  
    if (koreanTest($selection) === true) {
            console.log("korean passing");
            $select.append("<option>한국어</option>")
    }  
    if (chineseTest($selection) === true) {
            console.log("chinese passing");
            $select.append("<option>中文</option>") 
    }  
    if (vietnameseTest($selection) === true) {
            console.log("vietnamese passing");
            $select.append("<option>Tiếng Việt</option>")
    }       
});

I am aware that this code is repetitive and I'm not a fan of that. I'd also appreciate some pointers on how to clean this code up and make it so I'm adhering to DRY Don't Repeat Yourself coding. Thanks in advance.

m00saca
  • 363
  • 1
  • 7
  • 20

2 Answers2

3

In my code when you click on the drop down another drop down is created from the classes form the original options. I made a map of classes to languages that will be used to output the options in the new dropdown. I hope you understand. If you have any questions let me know.

$(function(){
  var map = {
    "eng" : "English",
    "esp" : "Español",
    "kor" : "한국어",
    "viet" : "Tiếng Việt",
    "chin" : "中文"
  }
  $("#docs").on("change", function(){
    //explanation of .attr()
    // lets say your html looks like this === 
    //<option id="specEd" class="eng kor viet esp chin">Special Education Programs</option> 
    // .attr("class") will create a string of all the classes like : 'eng kor viet esp chin'

    var selected = $("option:selected", this).attr("class");

    //then you split the string by spaces to get an arr like ["eng", "kor", "viet", "esp", "chin"]

    var arr = selected.split(" ");

    console.log(arr) //["eng", "kor", "viet", "esp", "chin"]


    //Next, remove the old dropdown that was appended. If `.added` was not there it will remove nothing
    //Then after it is removed append the new dropdown
    //so, on every change event you're removing the old and appending the new.

    $(".added").remove()
    $("body").append("<select class='added'>")

    //since the string of classes are split into an array you can use the array method of [forEach][1]
    arr.forEach(function(e){
     //`e` is each element in `arr`
      $(".added").append("<option>"+map[e]+"</option>");

     // so map[eng] == "English" then it goes to map[kor] etc..
     // you should know how JavaScript objects work

    })
  })
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<select id="docs">
  <option>- Choose a document to preview -</option>
  <option id="specEd" class="eng kor viet esp chin">Special Education Programs</option>
  <option id="parRight" class="eng kor esp">Special Ed. Parents Rights</option>
  <option id="cac" class="eng esp">CAC Brochure</option>
</select>
jack blank
  • 5,073
  • 7
  • 41
  • 73
  • This is exactly what I'm trying to do. Thanks a lot. I have a few questions. regarding `var selected = $("option:selected", this).attr("class");` Is this saying the variable `$selected` is equal to the selected option? I don't know what `this` is a reference to. Is it the selected option? You then are getting the class attribute with `.attr("class")? – m00saca Feb 19 '16 at 23:15
  • Really if you could just kind of walk me through it. I need help knowing exactly what is going on line by line. I'm new at this. – m00saca Feb 19 '16 at 23:33
  • 1
    Yes. `selected` is set to the selected option of the `#docs` drop down. The dropdown is the context (this). I also get the classes of the selected by doing `.attr()`. This gives you a list of the classes. You can provide a context object as the second parameter to a jquery selector as explained in this article http://weblogs.asp.net/dwahlin/jquery-tip-1-defining-a-context-when-using-selectors. BTW. This following would also work: `var selected = $(this).find('option:selected').attr("class");`. – jack blank Feb 19 '16 at 23:41
  • 1
    I added some comments to the answer. hope it helps. – jack blank Feb 19 '16 at 23:59
  • Now my final aim is to have all of these options link to a picture or preview of a PDF in a container off to the side. Could I still do that with this code? – m00saca Feb 21 '16 at 16:38
  • yes, I believe you can do that. If you want to make click events on dynamically created elements you should use the second parameter for the `.on` event. look at this question http://stackoverflow.com/questions/1359018/in-jquery-how-to-attach-events-to-dynamic-html-elements – jack blank Feb 21 '16 at 18:52
2

For the DRY coding, I would suggest replacing these functions

function englishTest(lang) {
    return lang.hasClass("eng");
}

With something like this

function testLanguage(selection, lang) {
    return selection.hasClass(lang);
}

And then calling it like

testLanguage($selection, "eng") === true

For your main question, you seem to be appending stuff always when the selection changes, but you never clear anything.

tperamaki
  • 1,028
  • 1
  • 6
  • 12
  • ooo thanks for the suggestion, I'll incorporate that into my code. Thanks for the tip. Yes you are correct, I am appending every time the selection changes but I don't know of a way to "clear" as you suggest. – m00saca Feb 19 '16 at 21:02
  • Try $select = $(""); – tperamaki Feb 19 '16 at 21:18
  • At the top of my .js file $select does = ("") – m00saca Feb 19 '16 at 21:33
  • I meant you should add it inside change function to clear it, not sure if that works, but the answer Jack gave seems to be better anyways. :) – tperamaki Feb 20 '16 at 09:34