Laboratorio: carga de combos
14:20 H (CET)| Temas: AJAX · Javascript · Laboratorio · PHP
Ayer nos preguntaban cómo cargar combos según lo que se seleccione en otro combo, y aunque no me quedó muy claro la duda que tenía, pues para intentar ayudarle, voy a explicar cómo hacerlo mediante tres posibilidades.
Primeramente explicaremos cómo hacerlo mediante el uso de iframes ocultos. Sí, no es nada web 2.0, pero no a todo el mundo se le da bien el desarrollo web, o no le gusta el uso de Ajax, o simplemente, como me pasa a mí, no nos dejan usar Ajax en los desarrollos del cliente (¡vete a saber por qué!).
Después lo haremos mediante Ajax (¡viva la web 2.0!), pero instanciando nosotros mismos el objeto XMLHttpRequest, para que los conceptos de Ajax no se pierdan dentro del uso de librerías, es importante conocer la base para luego usar una librería que te lo haga todo más fácil.
Y por último, ya no solo en plan web 2.0, sino en plan lo último de lo último, lo haremos usando la librería Prototype. Que la verdad sea dicha, no se trata de reinventar la rueda.
Antes de nada, explicar el proceso conjunto que tienen los tres modos. Existen dos combos (combo1 y combo2), de los cuales el primero contiene una información estática y el segundo se cargará según lo que se seleccione en el primer combo. Para ello el segundo combo estará vacio inicialmente y el primer combo llamará a la función carga cuando se modifique el valor.
<select id="combo1" onchange="carga(this.value)">
<option value=""></option>
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
<option value="D">D</option>
<option value="E">E</option>
</select>
<select id="combo2">
<option value="">Vacio</option>
</select>
Iframe
Debe existir un iframe oculto en el cual se cargará el resultado de la llamada a un script PHP cuando se modifique el valor del primer combo. Este script PHP devolverá un Javascript que modificará el valor del segundo combo.
<iframe id="oculto" src="" style="display:none"></iframe>
<script type="text/javascript">
var datos = new Array();
<?php
$val = $_GET["val"];
for ($i=1; $i<=5; $i++) {
?>
datos[datos.length] = '<?php echo $val.$i; ?>';
<?php
}
?>
var obj = parent.document.getElementById("combo2");
for (var i=0; i<obj.options.length; i++) {
obj.removeChild(obj.firstChild);
}
for (var i=0; i<datos.length; i++) {
var elem = datos[i];
obj.options[i] = new Option(elem);
}
</script>
Ajax
En este caso vamos a crearnos una instancia del objeto XMLHttpRequest y realizaremos una llamada Ajax a un script PHP que nos devolverá un XML con los nuevos datos del combo. Una vez recibidos, los recorreremos para modificar el segundo combo.
function ajaxobj() {
try {
_ajaxobj = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
_ajaxobj = new ActiveXObject("Microsoft.XMLHTTP");
} catch (E) {
_ajaxobj = false;
}
}
if (!_ajaxobj && typeof XMLHttpRequest!='undefined') {
_ajaxobj = new XMLHttpRequest();
}
return _ajaxobj;
}
function carga(val) {
var ajax = ajaxobj();
ajax.open("POST", "ajax.php", true);
ajax.onreadystatechange=function() {
if (ajax.readyState==4) {
var datos = (ajax.responseXML).firstChild;
var obj = document.getElementById("combo2");
for (var i=0; i<obj.options.length; i++) {
obj.removeChild(obj.firstChild);
}
for (var i=0; i<datos.childNodes.length; i++) {
var elem = datos.childNodes[i].firstChild.data;
obj.options[i] = new Option(elem);
}
}
}
ajax.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
ajax.send("&val="+val);
}
<?php
$val = $_POST["val"];
$xml .= '<datos>';
for ($i=1; $i<=5; $i++) {
$xml .= '<valor>'.$val.$i.'</valor>';
}
$xml .= '</datos>';
header('Content-type: text/xml');
echo $xml;
?>
Prototype
Realizarle mediante Prototype es lo mismo que en el ejemplo anterior, salvo que en vez de crearnos la instancia del objeto XHR, usaremos la funcionalidad que nos ofrece Prototype. Por eso el script PHP será el mismo.
<script type="text/javascript" src="prototype-1.4.0.js"></script>
function carga(val) {
var myAjax = new Ajax.Request('ajax.php',
{
method: 'post',
parameters: 'val='+val,
onComplete: modificaCombo
});
}
function modificaCombo(req) {
var datos = (req.responseXML).firstChild;
var obj = $("combo2");
for (var i=0; i<obj.options.length; i++) {
obj.removeChild(obj.firstChild);
}
for (var i=0; i<datos.childNodes.length; i++) {
var elem = datos.childNodes[i].firstChild.data;
obj.options[i] = new Option(elem);
}
}
Relacionados
Feedback (31) » Formulario
1. Baldemar ~ Viernes, 24 Nov 2006 | 16:55H:
Esta buena la informacion, gracias por compartirla creo que me servira para un proyecto que tengo que hacer para la esucela. =).
3. Danii ~ Martes, 30 Ene 2007 | 16:59H:
Esto esta pero que muy bien, pero mi pregunta es esta: ¿como se haria para rellenar la segunda combo con los datos de un directorio en local? Vamos que quiero meter el nombre de los ficheros que haya en un directorio.
Muchas gracias
5. danii ~ Miércoles, 31 Ene 2007 | 16:11H:
Si pero tengo otro problema y es que no se pueden pasar parametros de PHP a javascript. El programa funciona de la siguiente manera: en una combo tengo fechas(que son el nombre de los directorios creados) y en la otra, quiero cargar informes(que son los archivos que estan en esa carpeta) dependiendo de la fecha que se haya elegido.
Muchas gracias
6. Luis ~ Miércoles, 31 Ene 2007 | 19:03H:
Si, claro que se pueden pasar datos de PHP a Javascript, si te fijas en el ejemplo hay un PHP que devuelve un XML que el Ajax recibe y lo trata. Todo lo que necesitas está en el ejemplo, tan solo tu tienes que modificar el PHP para que en el XML que devuelve vayan los ficheros que te interesan.
Saludos
7. Danii ~ Jueves, 01 Feb 2007 | 12:48H:
Muchas gracias Luis por todo, pero sigo sin poder hacer la pagina(soy bastante inexperto en programacion PHP). Mi problema es que cargo la pagina con la combo1 rellena pero al hacer click en la combo1, no puedo ejecutar codigo PHP que es el que me deberia de rellenar la segunda combo.
O te lo explico de esta manera: Lo que quiero es que cuando haga click en una combo(que ya esta rellena) lanzar un evento que rellene otra combo (los datos de esta combo los recoge de un directorio creado).
Muchas gracias por todo y perdona si no me entero bien
8. Luis ~ Jueves, 01 Feb 2007 | 13:14H:
Hola Danii
Si es que en el ejemplo lo tienes todo hecho. Para que te sea más fácil, coges del ejemplo los archivos prototype*.* y ajax.php
En el HTML en el combo1 verás lo siguiente:
onchange="carga(this.value)
eso es que cuando se cambia el contenido del combo, se ejecuta la funcion de javascript carga, la cual llama al php ajax.php y recarga el combo
Tu tienes que cambiar ajax.php para que te lea un directorio y lo devuelva en el mismo formato que lo devuelve ahora. El resto ya lo hace la funcion modificaCombo automáticamente.
Saludos
9. Danii ~ Jueves, 01 Feb 2007 | 18:24H:
Hola Luis otra vez, ya se que soy un poco pesadito pero es que no me funciona. He probado el programa segun me he bajado y no me carga nada en la combo2. Mirando el codigo he visto la variable 'req' de modificaCombo que no se de donde la saca.
¿Necesito algo mas para que funcione el ejemplo segun me lo he bajado?
Un millon de gracias
10. Eva ~ Viernes, 16 Feb 2007 | 10:12H:
Hola Luis:
¿Cómo podría cargar el 2º combo con datos que obtengo de una consulta de una base de datos mysql?
11. Eva ~ Viernes, 16 Feb 2007 | 10:12H:
Hola Luis:
¿Cómo podría hacer para cargar el 2º combo con datos que obtengo de una consulta de una base de datos mysql?
Saludos
12. Luis ~ Viernes, 16 Feb 2007 | 12:04H:
Hola Eva.
Tienes que modificar el fichero php, como verás yo devuelvo un XML inventado, tu en vez de hacer el bucle for que yo uso, deberías usar el bucle que uses en la recuperación de datos de la consulta MySQL e introducirlos dentro de las etiquetas <valor> del XML que se devuelve.
Saludos
13. Eva ~ Lunes, 19 Feb 2007 | 08:55H:
Hola Luis otra vez:
He probado a poner los datos que recupero de mi bucle for dentro de las etiquetas pero no se me carga el segundo combo. He comprobado si recogía el valor de la variable var en el codigo php (echo ($val)), pero parece que no se recoge. Tampoco tengo muy claro como poner el código entre las etiquetas, para que se recoja el valor de la select y lo que se va a mostrar, es decir, como poner: subcategoria
Muchas gracias
14. Enrique ~ Jueves, 22 Feb 2007 | 21:41H:
Hola, tengo un problemita de espacio en mi pagina, quiero que exista un solo combo y que de acuerdo al valor que le de en el primero me cambie los valores nuevos q le ingrese en ese mismo combo. espero y me haya explicado. gracias
15. PAMR ~ Lunes, 26 Mar 2007 | 21:31H:
Por favor necesito me den un alcance de cómo hacer un tercer combo. Gracias
17. Javier ~ Viernes, 30 Mar 2007 | 03:44H:
Que tal:
Quiero ver si me puedes ayudar, tengo 3 combos que lo lleno con la base de datos y varias cajas de texto las cuales, dependiendo de lo que ingresen lo pueda comparar con lo que tengo en la base de datos y mostralo, no se si me puedas ayudar a explicarme como le puedo hacer o no se si me explique bien lo que quiero hacer, de antemano gracias.
19. Deysi ~ Martes, 03 Abr 2007 | 21:56H:
Hola tengo varios combos pero deseo que al elegir un combo en donde muestro productoy quiero que se carge en un imput datos de ese producto como el Precio.
Ya lo hice pero me lo coloca en otro combo.alguien me puede ayudar o enviarme un ejemplo de como hacer
De antemano Gracias
DEYSI
20. Javier ~ Viernes, 06 Abr 2007 | 04:42H:
Gracias Luis, perdón por contestar hasta hoy pero ando medio apurado con unos examenes que estoy presentando, gracias de nuevo.
24. Hugo ~ Martes, 24 Abr 2007 | 18:58H:
Perdón,
no me da errores de javascript. Es que había probado poniendo los parentesis al hacer la llamada a la funcion modificaCombo(). Ya he visto que la variable req recibe el objeto xml.
Pero sigue sin salir nada en el segundo combo.
Con tus ficheros de ejemplo en Firefox no sale nada en el segundo combo, y en explorer se abre el combo como si hubieran varios valores pero no aparece nada dentro.
30. PAMR ~ Lunes, 23 Jul 2007 | 23:10H:
como puedo adicionar otros combos, deseo que sean 4 o 5 combos.
31. Martokingv ~ Jueves, 20 Dic 2007 | 17:29H:
Hola Luis, he empleado tu ejemplo, usando el método Prototype, para la siguiente estructura de combos:
c1= contiene c11 c12 c13 c14 c15 c16 c17
c2: dependiendo del valor c1...
c11=c211
c12=c221
c13=c231
c14=c241 - c242 - c243 - c244
El problema me pasa si selecciono c14, momento en el que c2 contiene todos los valores indicados, pero si cambio la selección de c1 a cualquier otro, el resultado es
c11=c11 - c244
Para evitarlo he modificado lo siguiente:
for (var i=0; i <(datos.childNodes.length+1); i++)

