How can I use this JavaScript to have one select option be dependent on the previous select option?

284 views Asked by At

Here is my problem. I am trying to have this second select option be dependent on the previous select option. The first select option determines color of shoe. The second select option, size, is based on the color of the shoe. How can I make this dynamic enough to change available sizes based on color?

Here is my code:

<SCRIPT type="text/javascript">
    
$(document).ready(function()
{
    $("#color").change(function()
    {
        var element = $(this);
        
        if(element.val() === "brn")
        {
            $("#size").append('<option value="5">5</option>');
            $("#size").append('<option value="6">6</option>');
            $("#size").append('<option value="7">7</option>');
            $("#size").append('<option value="8">8</option>');
            $("#size").append('<option value="9">9</option>');
            $("#size").append('<option value="10">10</option>');
            $("#size").append('<option value="11">11</option>');
            $("#size").append('<option value="12">12</option>');
            $("#size").append('<option value="13">13</option>');
        }
        
        else if(element.val() === "blk")
        {
            $("#size").append('<option value="7">7</option>');
            $("#size").append('<option value="8">8</option>');
            $("#size").append('<option value="9">9</option>');
            $("#size").append('<option value="10">10</option>');
            $("#size").append('<option value="11">11</option>');
            $("#size").append('<option value="12">12</option>');
            $("#size").append('<option value="13">13</option>');
        }
        
         else if(element.val() === "nav")
        {
            $("#size").append('<option value="5">5</option>');
            $("#size").append('<option value="6">6</option>');
            $("#size").append('<option value="7">7</option>');
            $("#size").append('<option value="8">8</option>');
            $("#size").append('<option value="9">9</option>');
            $("#size").append('<option value="10">10</option>');
        }

        else if(element.val() === "sbl")
        {
            $("#size").append('<option value="5">5</option>');
            $("#size").append('<option value="6">6</option>');
            $("#size").append('<option value="7">7</option>');
            $("#size").append('<option value="8">8</option>');
            $("#size").append('<option value="9">9</option>');
            $("#size").append('<option value="10">10</option>');
        }

        else if(element.val() === "pnk")
        {
            $("#size").append('<option value="5">5</option>');
            $("#size").append('<option value="6">6</option>');
            $("#size").append('<option value="7">7</option>');
            $("#size").append('<option value="8">8</option>');
            $("#size").append('<option value="9">9</option>');
            $("#size").append('<option value="10">10</option>');
        }
    });
});
<form action="#" method="post">
    <p align="center">
        <label for="color">Color: 
            <select name="color" id="color">
                <option value="brn">Brown</option>
                <option value="blk">Black</option>
                <option value="nav">Navy</option>
                <option value="sbl">Sky Blue</option>
                <option value="pnk">Pink</option>
            </select>
        </label>
    </p>

    <p align="center">
        <label for="size">Size: 
            <select name="size" id="size">
                function();
            </select>
        </label>
    </p>

    <div align="center">  
        <input type="submit" value="Add To Cart" />
    </div>
</form>

3

There are 3 answers

2
jeremysawesome On

How can I make this dynamic enough to change available sizes based on color?

The base problem as Glorfindel stated is that your quotes need to be escaped. (Also, since your values for the sizes are the same as your options you don't actually need to specify a value for the sizes).

However, I thought I'd mention a few other things I noticed. You state that you'd like to make this dynamic enough to change the available sizes based on color. Your JavaScript will actually append the new values whenever you change the color, meaning that switching from one color to the next will result in the first colors size options and the second options.

In order to fix this you will want to call .empty() on your size element so that the new options will replace the older ones.

We can make this even better though!

By calling $('#size') on almost every line we are creating a brand new jQuery object for each addition to the option element. Also, we end up searching the DOM for that selector as well. You can make this perform better by doing a couple of different things.

Take advantage of jQuery chaining.

Most methods in jQuery return the original object after they are done executing. This means that you can continue running jQuery methods one after another. By chaining your calls together you ensure that you do not have to create a new jQuery object on each line. This makes your JavaScript perform better (if even a little bit).

Example:

// without chaining, creates a new jquery object on each line
$("#size").append("<option>7</option>");
$("#size").append("<option>8</option>");
$("#size").append("<option>9</option>");
$("#size").append("<option>10</option>");
$("#size").append("<option>11</option>");
$("#size").append("<option>12</option>");
$("#size").append("<option>13</option>");

// using chaining instead - uses the original jQuery object
$("#size").append("<option>7</option>")
    .append("<option>8</option>")
    .append("<option>9</option>")
    .append("<option>10</option>")
    .append("<option>11</option>")
    .append("<option>12</option>")
    .append("<option>13</option>");

So. if we add chaining we end up with some JavaScript that performs better. But we are also calling .append() a lot. Each time we call .append() we are also triggering a reflow.

Reduce Reflows

Rather than calling append multiple times adding an element one at a time, we can call append once and add the elements we want once. This makes it so we don't tell the browser to reflow the document more than is necessary. (Aside: this concept is similar to what RActive and React do by creating a VirtualDOM).

Well, since we already know what is going to be appended we can simply remove all the appends and replace them with one gigantic string.

$("#size").append("<option>7</option><option>8</option><option>9</option><option>10</option><option>11</option><option>12</option><option>13</option>");

But - that makes my eyes bLLeeed. It's ugly. So let's refactor this some more.

Continuing to Refactor

The only thing different between one option and the next option is the actual numeric size. The opening <option> and closing </option> are the same for each one. Maybe we move this out to a method like getOptions(color)?

We are using element.val() a lot to get the selected color. However, we don't use the element for anything else. Maybe we could just store that color in a variable - so we don't have to get it all of the time? var selectedColor = element.val();

Also, we could probably get rid of the if statements if we setup an object to contain our sizes. That object would consist of color key values, and then an array of sizes for those keys.

Eventually, we might end up with something like this:

$("#color").change(function () {
    var selectedColor = $(this).val();

    // store an object with our sizes for each color
    var sizes = {
        'blk': [5, 6, 7, 8, 9, 10, 11, 12, 13],
            'brn': [7, 8, 9, 10, 11, 12, 13],
            'nav': [5, 6, 7, 8, 9, 10],
            'sbl': [5, 6, 7, 8, 9, 10],
            'pnk': [5, 6, 7, 8, 9, 10],
    }

    function getOptions(color) {
        // return an empty string if we don't have sizes for the given color
        if (!sizes.hasOwnProperty(color)) return '';
        var options = '';
        for (var i in sizes[color]){ 
            options = options + '<option>' + sizes[color][i] + '</option>'; 
        }
        return options;
    }

    // use .html() instead of .empty().append() to replace the entire contents of the element
    $("#size").html(getOptions(selectedColor));
});

And in fiddle form: http://jsfiddle.net/h1navan2/3/

It's a start. You might find ways of refactoring this more. However, remember the key things that we did.

  1. We try to only create the jQuery object once. If we have to use it more than once we can use chaining to use the same jQuery object multiple times. Or, if we have to use it in multiple places then we can store it in a variable: var $sizes = $('#sizes');. Then we can use that variable.
  2. We reduced the reflow/repaint by only appending to the DOM once.

In any case, I know this is much more than what you bargained for. But maybe it'll help in the future. Hopefully it's helpful.

Good luck Javascripting! :)

0
Glorfindel On

The problem lies in your strings, e.g. "<option value="5">5</option>". You have to escape the double quote, or use single quotes instead:

'<option value="5">5</option>'

or, equally valid:

"<option value='5'>5</option>"

Also, pay attention to Stryner's comment.

0
Tahir Ahmed On

Your options need to wrapped in single quotes as @Glorfindel pointed out. Also, you might want to empty() the existing options before populating new ones.

i.e.:

$("#size").empty();
$("#size").append('<option value="5">5</option>');
...