nicorellius
nicorellius

Reputation: 4043

Cascade Select with Existing Multiple Select Form

I'm working with a PHP output form that works in conjunction with JavaScript to create a composite file name that becomes a download.

I have implemented this post as well:

Three Select Boxes Interacting to Yield One Result - HTML, JavaScript or jQuery

So now I have an existing multiple selection form:

<select id="one">
    <option value="default">Select Product</option>
    <option class="s" value="1">product1</option>
    <option class="q" value="2">product2</option>
    <option class="q" value="3">product3</option>
</select>

<select id="two">
    <option value="default">Select Version</option>
    <option class="l" value="4">product4</option>
    <option class="l" value="5">product5</option>
    <option class="c" value="6">product6</option>
</select>

<select id="three">
    <option value="default">Select OS</option>
    <option class="o" value="7">product7</option>
    <option class="o" value="8">product8</option>
    <option class="o" value="9">product9</option>
</select>

<select id="three">
    <option value="default">Select Architecture</option>
    <option class="a" value="10">product10</option>
    <option class="a" value="11">product11</option>
    <option class="a" value="12">product12</option>
</select>

When the button is clicked it concatenates the strings and creates an URL that is a download installer. This works fine and in most cases yields a valid file to download.

But there are several options that are invalid. I added the classes above just for this post, because it's clear they are in the corresponding groups.

Now, the question here is, how do I get the cascading affect with this existing form? The PHP and JavaScript I'm using is:

From the PHP file:

$output .=  '<div><p class="download-button"><a id="viewer-dl"';
$output .=  ' onclick="download_file(document.getElementById(';
$output .=  "'" . $product_id . "'" . ').value, document.getElementById(';
$output .=  "'" . $version_id . "'" . ').value, document.getElementById(';
$output .=  "'" . $os_id      . "'" . ').value, document.getElementById(';
$output .=  "'" . $arch_id    . "'" . ')"></a></p></div>';

From the JavaScript file:

$(function() {
    $("#viewer-dl").click(function() {
        download_viewer( $('#product_id').val(), $('#version_id').val(), 
            $('#os_id').val(), $('#arch_id').val());
    });
});

function download_file(version_id, os_id, arch_id) {

    if (product_id == 'default' && version_id == 'default' && 
        os_id == 'default' && arch_id == 'default') {
        return;
    }

    else if (product_id != 'default') {
        window.location = 'mysite.com/download/Install_' +
            product_id + '_' + version_id + '_' + arch_id + '.exe';
    }
}

What I'm trying to do is when the s class is selected, I want the the l and c classes selected for the next selection, but when the q class is selected, I only want the c class selected. The OS, Architecture selections I want to be there for all choices, hence the classes are the same for these.

Upvotes: 0

Views: 3119

Answers (2)

user688074
user688074

Reputation:

I created a demo using lists instead of selects: http://jsfiddle.net/MQ3u3/5/

<ul id="parents"></ul>
<ul id="children"></ul>
<div id="bucket"></div>


var data = [{
    "id": 1,
        "name": "Item1",
        "children": [{
        "id": 1,
            "name": "child one"
    }, {
        "id": 2,
            "name": "child two"
    }]
}, {
    "id": 2,
        "name": "Item2",
        "children": [{
        "id": 1,
            "name": "child three"
    }, {
        "id": 2,
            "name": "child four"
    }]
}, {
    "id": 3,
        "name": "Item3",
        "children": [{
        "id": 1,
            "name": "child five"
    }, {
        "id": 2,
            "name": "child six"
    }]
}];
$(function () {
    for (var i = 0; i < data.length; i++) {
        createParentItem(i);
    }
    $('li.parent').on('click', function () {
        $('#children li').remove();
        var parentId = $(this).attr('data-id');

        for (var i1 = 0; i1 < data.length; i1++) {
            if (parentId == data[i1].id) {
                for (var i2 = 0; i2 < data[i1].children.length; i2++) {
                    createChildItem(i1, i2);
                }
            }
        }
        $('li.child').off();
        $('li.child').on('click', function () {
            var parentId = $(this).attr('parent-data-id');
            var childId = $(this).attr('child-data-id');
            for (var i1 = 0; i1 < data.length; i1++) {
                if (parentId == data[i1].id) {
                    for (var i2 = 0; i2 < data[i1].children.length; i2++) {

                        if (childId == data[i1].children[i2].id) {
                            addToBucket(i1, i2);
                        }
                    }
                }
            }
        });
    });
});
function createParentItem(index) {
    var li = $('<li>', {
        class: 'parent',
            "data-id": data[index].id,
        text: data[index].name
    });
    $('ul#parents').append(li);
}
function createChildItem(pIndex, cIndex) {
    var li = $('<li>', {
        class: 'child',
            "parent-data-id": data[pIndex].id,
            "child-data-id": data[pIndex].children[cIndex].id,
        text: data[pIndex].children[cIndex].name
    });
    $('ul#children').append(li);
}
function addToBucket(pIndex, cIndex) {
    var child = data[pIndex].children[cIndex];
    var childElm = $('<span>', {
        text: child.name + ' '
    });
    $('#bucket').append(childElm);
}

Upvotes: 0

TCFDS
TCFDS

Reputation: 622

I created small demo what you can do to JSFiddle: http://jsfiddle.net/nx6yF/

Basically what I did that I hided all other selects but first, then if first select changes you have to check the selection and show second select

$("#one").change(function() {
        var val = $(this).val();
        if (val != "default") {
            $("#two").show();
        }
});

You also need to decide which options to show in second select. Maybe class is not the most practical thing to handle this, but it could be something like this:

 var is_q = $("#one > option[value="+val+"]").hasClass("q");
 $("#two > option").each(function() {
      if (!$(this).hasClass("c") && $(this).val() != "default") {
          if (is_q) {
              $(this).attr("disabled",true);
          }
          else{
              $(this).attr("disabled",false);
          }
      }
 });

I used here disabling options but as well it would be possible to hide them. Anyway disabled / hided selection should be also changed to default if selected, in order to make form work correctly with multiple selects

After this you can check if selection two is selected and then show select three. Of course, is some select has value default, then next selects should be hided.

I'm not sure is there any easy answer, how to create cascading effect - it just needs coding to do it.

Upvotes: 1

Related Questions