Les comparto esta pequeña librería que hice para hacer Selects Dependientes de N niveles con AJAX.
Su uso es bastante simple, solo es instanciar el select y pasar quien es el que depende y el URL para cargar los datos, posteriormente en ese URL van a recibir por GET dos datos, controlName (el nombre del control) y selectedId (el valor que selecciono).
La clase espera recibir un arreglo codificado en JSON, donde cada elemento es un objeto, con una propiedad text, y otra value, de esta forma:
Código:
La forma de uso es bastante simple, basta con tener un HTML:[ { text: "Texto a mostrar", value: "valor del option" }, { text: "Texto 2", value: "valor2" }, .... { text: "Texto n", value: "ValorN" } ]
Código HTML:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <script type="text/javascript" src="prototype.js"></script> <script type="text/javascript" src="dependant.js"></script> <title>Demo Selects Dependientes</title> </head> <body> <select name="sel1" id="sel1"> <option value="">- Selecciona -</option> <option>Mascotas</option> <option>Carros</option> </select> <select name="sel2" id="sel2"><option></option></select> <select name="sel3" id="sel3"><option></option></select> <script type="text/javascript"> Event.observe(window, 'load', function() { var sel3 = new HTMLSelect( 'sel3' ); var sel2 = new dependantSelectAJAX( 'sel2', sel3, 'loader.php' ); var sel1 = new dependantSelectAJAX( 'sel1', sel2, 'loader.php' ); }); </script> </body> </html>
Dejo un pequeño ejemplo de como cargar los datos via PHP, aunque es independiente del lenguaje, el único requisito es que los datos vengan en JSON y con la estructura mencionada mas arriba:
Código PHP:
<?php
$mascotas = array( array( "text" => "Gato", "value" => "cat" ), array( "text" => "Perro", "value" => "dog" ), array( "text" => "Pajaro", "value" => "bird" ) );
$carros = array( array( "text" => "BMW", "value" => "bmw" ), array( "text" => "Lamborghini", "value" => "lamb" ), array( "text" => "Ferrari", "value" => "ferr" ) );
$mascotas_acc_cat = array( array( "text" => "Collar" ), array( "text" => "Estambre" ), array( "text" => "Arena" ) );
$mascotas_acc_dog = array( array( "text" => "Collar" ), array( "text" => "Correa" ), array( "text" => "Pelota" ) );
$mascotas_acc_bird = array( array( "text" => "Jaula" ), array( "text" => "Alpiste" ) );
$carros_color_bmw = array( array( "text" => "Azul" ), array( "text" => "Negro" ) );
$carros_color_lamb = array( array( "text" => "Azul" ), array( "text" => "Amarillo" ), array( "text" => "Rojo" ) );
$carros_color_ferr = array( array( "text" => "Rojo" ) );
switch( $_GET['controlName'] ) {
case 'sel1':
switch( $_GET['selectedId'] ) {
case 'Mascotas':
$result = $mascotas;
break;
case 'Carros':
$result = $carros;
break;
}
break;
case 'sel2':
switch( $_GET['selectedId'] ) {
case 'cat':
$result = $mascotas_acc_cat;
break;
case 'dog':
$result = $mascotas_acc_dog;
break;
case 'bird':
$result = $mascotas_acc_bird;
break;
case 'bmw':
$result = $carros_color_bmw;
break;
case 'lamb':
$result = $carros_color_lamb;
break;
case 'ferr':
$result = $carros_color_ferr;
break;
}
}
echo json_encode( $result );
exit();
?>
Código:
Requiere de la libreria Prototype versión 1.6 minimo debido a la nueva forma de declarar clases.var DataStore = Class.create(Enumerable, { initialize: function( store ) { if( store == null ) { store = []; } this._store = store; }, addItem: function( text, value ) { if( value == null ) { value = text; } this._store.push( {text: text, value: value } ); }, removeItem: function( idx ) { this._store.splice( idx, 1 ); }, clear: function() { this._store = []; }, size: function() { return this._store.length; }, inspect: function() { alert( this._store.inspect() ); }, _each: function(iterator) { for (var i = 0; i < this._store.length; i++) { var value = this._store[i]; iterator(value); } } }); var HTMLSelect = Class.create({ initialize: function( element ) { this.element = $(element); this.element.onchange = this.onChange.bindAsEventListener(this); this.element.onclick = this.onClick.bindAsEventListener(this); this.element.onfocus = this.onFocus.bindAsEventListener(this); var store = new DataStore(); var opts = this.element.options; for(var i = 0; i < opts.length; i++ ) { var el = opts[i]; store.addItem( el.text, el.value ); } this.store = store; }, setStore: function( ds ) { this.store = ds; }, reload: function() { this.empty(); var num = 0; this.store.each(function(item) { this.addOption(item.text, item.value); num++; }.bind(this)); }, onChange: function(e) {}, onClick: function(e) {}, onFocus: function(e) {}, onEmpty: function() { return true; }, selectIndex: function( index ) { this.element.selectedIndex = index; }, selectOption: function( option ) { var size = this.element.length; var found = false; for(i = 0; i < size; i++) { var el = this.element.options[i].text; if( el == option ) { found = true; break; } } if( found ) { this.selectIndex(i); this.onChange(); } }, countOptions: function() { return this.element.length; }, getSelectedOption: function() { var op = this.element.options[this.element.selectedIndex]; return { value: op.value, text: op.text }; }, getValue: function() { var op = this.element.options[this.element.selectedIndex]; var ret = ""; ret = op.value; if( ret == "" ) { ret = op.text; } return ret; }, empty: function() { if( this.onEmpty() ) { this._empty(); } }, addOption: function( text, value ) { if( value == null ) { value = text; } var op = new Option( text, value ); var idx = this.element.length; this.element.options[idx] = op; return idx; }, deleteOption: function( index ) { if( this.element.length > 0 && index > 0 ) { this.element.options[index] = null; } }, selectAllOptions: function() { var size = this.element.length - 1; for(i = size; i>=0; i--) { this.element.options[i].selected = true; } }, getSelectedOptions: function() { var texts = []; var size = this.element.length - 1; for(i = size; i>=0; i--) { if( this.element.options[i].selected === true ) { texts.push(this.element.options[i].text); } } return texts; }, _empty: function() { this.element.options.length = 0; } }); var dependantSelectAJAX = Class.create(HTMLSelect, { initialize: function( $super, select, child, url ) { $super( select ); if( typeof( select ) == "string" ) { this.name = select; } else { this.name = select.name; } this.child = child; this.url = url; }, onChange: function(e) { this.child.empty(); var value = this.getValue(); if( value != "" ) { var request = new Ajax.Request( this.url, { method: 'get', parameters: {controlName: this.name, selectedId: value}, onSuccess: function( transport ) { var store = transport.responseText.evalJSON(true); if( typeof store.error != "undefined" ) { alert( store.error ); } else { this.child.setStore(new DataStore(store)); this.child.reload(); var size = this.child.countOptions(); if( size == 1 ) { this.child.onChange(); } } }.bind(this), onFalure: function(t) { alert( "Error in request" ); } }); } }, onEmpty: function() { this.child.empty(); return true; } });
Saludos y espero les sea de utilidad.