views:

19310

answers:

5

Using answers to this question, I have been able to populate a select box based on the selection of another select box. ( I posted my answer here) Pulling the data from an array structure built server-side, stored in a .js file and referenced in the html page.

Now I would like to add a third select box. If I had 3 sets of data (model, make, options) something like this (pseudo code):

cars : [Honda[Accord[Lx, Dx]], [Civic[2dr, Hatchback]],
   [Toyota[Camry[Blk, Red]], [Prius[2dr,4dr]]

Ex: If Honda were selected, the next select box would have [Accord Civic] and if Accord were selected the next select box would have [Lx Dx]

How can I

1) create an array structure to hold the data? such that

2) I can use the value from one select box to reference the needed values for the next select box

Thanks

EDIT

I can create the following, but can't figure out the references in a way that would help populate a select box

var cars = [
 {"makes"  : "Honda",
  "models"  : [
 {'Accord' : ["2dr","4dr"]} ,
 {'CRV'  : ["2dr","Hatchback"]} ,
 {'Pilot': ["base","superDuper"] } ]
 },
 {"makes"   :"Toyota",
  "models"  : [
 {'Prius'   : ["green","reallyGreen"]} ,
 {'Camry'   : ["sporty","square"]} ,
 {'Corolla' : ["cheap","superFly"] } ]
 } ] ;     

 alert(cars[0].models[0].Accord[0]); ---> 2dr
+1  A: 

You should take a look here for select box manipulation. For what you want, i think JSON will do the right job for you. Anyhow, if i were you, i will do this way: When I change first select, i do an ajax request. With ajax response, i will populate the second box. Same for second box and there you have the third box populated with right data.

Ionut Staicu
+16  A: 

I prefer data structure like this:

var carMakers = [
    { name: 'Honda', models: [
      { name: 'Accord', features: ['2dr', '4dr'] },
      { name: 'CRV', features: ['2dr', 'Hatchback'] },
      { name: 'Pilot', features: ['base', 'superDuper'] }
     ]},

    { name: 'Toyota', models: [
      { name: 'Prius', features: ['green', 'superGreen'] },
      { name: 'Camry', features: ['sporty', 'square'] },
      { name: 'Corolla', features: ['cheap', 'superFly'] }
     ]}
];

Given the three select lists with id's: 'maker', 'model' and 'features' you can manipulate them with this (I believe this is pretty self explanatory):

// returns array of elements whose 'prop' property is 'value'
function filterByProperty(arr, prop, value) {
    return $.grep(arr, function (item) { return item[prop] == value });
}

// populates select list from array of items given as objects: { name: 'text', value: 'value' }
function populateSelect(el, items) {
    el.options.length = 0;
    if (items.length > 0)
     el.options[0] = new Option('please select', '');

    $.each(items, function () {
     el.options[el.options.length] = new Option(this.name, this.value);
    });
}

// initialization
$(document).ready(function () {
    // populating 1st select list
    populateSelect($('#maker').get(0), $.map(carMakers, function(maker) { return { name: maker.name, value: maker.name} }));

    // populating 2nd select list
    $('#maker').bind('change', function() {
     var makerName = this.value,
      carMaker = filterByProperty(carMakers, 'name', makerName),
      models = [];

     if (carMaker.length > 0)
      models = $.map(carMaker[0].models, function(model) { return { name: model.name, value: makerName + '.' + model.name} });

     populateSelect($('#model').get(0), models);
     $('#model').trigger('change');
    });

    // populating 3rd select list
    $('#model').bind('change', function () {
     var nameAndModel = this.value.split('.'),
      features = [];

     if (2 == nameAndModel.length) {
      var makerName = nameAndModel[0], 
       carModel = nameAndModel[1],
       carMaker = filterByProperty(carMakers, 'name', makerName);

      if (carMaker.length > 0) {
       var model = filterByProperty(carMaker[0].models, 'name', carModel)

       if (model.length > 0)
        features = $.map(model[0].features, function(feature) { return { name: feature, value: makerName + '.' + carModel + '.' + feature} })
      }
     }

     populateSelect($('#feature').get(0), features);
    })

    // alerting value on 3rd select list change
    $('#feature').bind('change', function () { 
     if (this.value.length > 0)
      alert(this.value);
    })
});
Marko Dumic
thanks for the effort you put into your answer. I tried your code and it worked, but I don't have time right now to learn exactly how it works...will come back to it later..but I'm using the array structure...and I think I now understand how to create these arrays. Thanks again
CarolinaJay65
The data structure is actually a Javascript object. You can find here a decent JSON tutorial: http://www.hunlock.com/blogs/Mastering_JSON_%28_JavaScript_Object_Notation_%29
BalusC
Using $.grep and $.map for this is just the masters stroke. Fantastic solution, I just used it as a basis for something similar and feel like a better programmer for it.Awesome solution.
hendrixski
+1  A: 

Thanks to the answer from @Marko Dunic, I was able to build an array (data) structure that can be referenced to populate 3 select boxes. I didn't use the implementation code only because I didn't completely understand it...it works as posted. I will come back to this code later as I learn jQuery. My code is posted below (obviously, your reference to jQuery may be different)

<html><head>
<script language="Javascript" src="javascript/jquery-1.2.6.min.js"></script>
<script type="text/JavaScript">
var cars = [
{ name: 'Honda', models: [
{ name: 'Accord', features: ['2dr', '4dr'] },
{ name: 'CRV', features: ['2dr', 'Hatchback'] },
{ name: 'Pilot', features: ['base', 'superDuper'] }
   ]},
{ name: 'Toyota', models: [
{ name: 'Prius', features: ['green', 'superGreen'] },
{ name: 'Camry', features: ['sporty', 'square'] },
{ name: 'Corolla', features: ['cheap', 'superFly'] }
   ]
 }
];
$(function() {
var options = '' ;
for (var i = 0; i < cars.length; i++) {
    var opt = cars[i].name ;
    if (i == 0){  options += '<option selected value="' + opt + '">' + opt + '</option>'; }
    else {options += '<option value="' + opt + '">' + opt + '</option>'; } 
}
$("#maker").html(options);   // populate select box with array

var options = '' ;
for (var i=0; i < cars[0].models.length; i++) { 
    var opt = cars[0].models[0].name ;
    if (i==0){options += '<option selected value="' + opt + '">' + opt + '</option>';}
    else {options += '<option value="' + opt + '">' + opt + '</option>';} 
}
$("#model").html(options);   // populate select box with array

var options = '' ;
for (var i=0; i < cars[0].models[0].features.length; i++) { 
    var opt = cars[0].models[0].features[i] ;
    if (i==0){options += '<option selected value="' + opt + '">' + opt + '</option>';}
    else {options += '<option value="' + opt + '">' + opt + '</option>';}
}
$("#feature").html(options);   // populate select box with array

$("#maker").bind("click",
    function() {
        $("#model").children().remove() ;       // clear select box
        for(var i=0; i<cars.length; i++) {
            if (cars[i].name == this.value) {
                var options = '' ;
                for (var j=0; j < cars[i].models.length; j++) { 
                    var opt= cars[i].models[j].name ;
                    if (j==0) {options += '<option selected value="' + opt + '">' + opt + '</option>';}
                    else {options += '<option value="' + opt + '">' + opt + '</option>';} 
                }
                break;
            }
        }
        $("#model").html(options);   // populate select box with array

        $("#feature").children().remove() ;     // clear select box
        for(var i=0; i<cars.length; i++) {
            for(var j=0; j<cars[i].models.length; j++) {
                if(cars[i].models[j].name == $("#model").val()) {
                    var options = '' ;
                    for (var k=0; k < cars[i].models[j].features.length; k++) { 
                        var opt = cars[i].models[j].features[k] ;
                        if (k==0){options += '<option selected value="' + opt + '">' + opt + '</option>';}
                        else {options += '<option value="' + opt + '">' + opt + '</option>';}
                    }
                    break;
                }
            }
        }
        $("#feature").html(options);   // populate select box with array
    });

    $("#model").bind("click",
        function() {
            $("#feature").children().remove() ;     // clear select box
            for(var i=0; i<cars.length; i++) {
                for(var j=0; j<cars[i].models.length; j++) {
                    if(cars[i].models[j].name == this.value) {
                        var options = '' ;
                        for (var k=0; k < cars[i].models[j].features.length; k++) { 
                            var opt = cars[i].models[j].features[k] ;
                            if (k==0){options += '<option selected value="' + opt  + '">' + opt  + '</option>';}
                            else {options += '<option value="' + opt  + '">' + opt  + '</option>';}
                        }
                        break ;
                    }
                }
            }
            $("#feature").html(options);   // populate select box with array
    });
});
</script>
</head> <body>
<div id="selection">
<select id="maker"size="10" style="{width=75px}"></select>
<select id="model" size="10" style="{width=75px}"></select>
<select id="feature" size="10"style="{width=75px}"></select>
</div></body></html>
CarolinaJay65
+1 for filling in a gaping hole in my jQuery+JSON knowledge. Thank you :)
Zoe
A: 

Thanks Marko for posting your working example. I'm in the crazy event that I need to populate 4 related select boxes. Let's say the fourth would be for example:

transmission: ['automatic', 'manual']

My JavaScript/JQuery skills were not high enough to modify the script for this. Could you or somebody else be kind enough to explain how to add the fourth level?

iisakki
A: 

Hi the above script is not working in Chrome, any suggestion,please

Harish