Ver Mensaje Individual
  #14 (permalink)  
Antiguo 17/01/2016, 22:11
Avatar de Alexis88
Alexis88
Philosopher
 
Fecha de Ingreso: noviembre-2011
Ubicación: Tacna, Perú
Mensajes: 5.552
Antigüedad: 13 años, 2 meses
Puntos: 977
Respuesta: Botón submit para selects anidados

Si los <select> cargarán la información de manera dinámica, es decir, elegirás una opción del primer <select> y luego tendrán que cargar opciones relacionadas a dicha opción pero en el segundo <select> y la misma situación será con el segundo y tercer <select>, puedes hacer lo que explicaré a continuación.

1. Dentro del formulario, añade tres secciones:
Código HTML:
Ver original
  1. <form id="ejemplo">
  2.     <section></section>
  3.     <section></section>
  4.     <section></section>
  5. </form>

2. Crea una función que realizará las respectivas peticiones asíncronas (AJAX) para obtener los datos de la base de datos con los cuales armarás los <select>:
Código Javascript:
Ver original
  1. var ajax = function(opciones){
  2.     var xhr = new XMLHttpRequest(),
  3.         url = "tuArchivo.php?nivel=" + opciones.nivel;
  4.  
  5.     if (opciones.valor){
  6.         url += "&valor=" + opciones.valor;
  7.     }
  8.  
  9.     xhr.open("GET", url, true);
  10.     xhr.send();
  11.     xhr.addEventListener("load", function(){
  12.         if (this.status == 200){
  13.             opciones.seccion.innerHTML = this.responseText;
  14.         }
  15.     }, false);
  16. };

3. Crea el script en el archivo PHP que procesará esta petición, realizará la búsqueda en la base de datos y creará el respectivo <select>:
Código PHP:
Ver original
  1. <?php
  2. $conexion = new mysqli('servidor', 'usuario', 'clave', 'base de datos');
  3. if ($conexion->connect_errno) exit($conexion->connect_errno . ': ' . $conexion->connect_error);
  4.  
  5. $nivel = $conexion->real_escape_string(strip_tags(trim($_GET['nivel'])));
  6. $valor = isset($_GET['valor']) ? $conexion->real_escape_string(strip_tags(trim($_GET['valor']))) : '';
  7.  
  8. $campoCodigo = 'tabla' . $nivel . '_codigo';
  9. $campoNombre = 'tabla' . $nivel . '_nombre';
  10. $campoClave = 'tabla' . $nivel . '_campoClave';
  11. $tabla = 'tabla' . $nivel;
  12.  
  13. $consulta = "SELECT $campoCodigo, $campoNombre FROM $tabla";
  14. if (strlen($valor)){
  15.     $consulta .= " WHERE $campoClave = '$valor'";
  16. }
  17.  
  18. $resultados = $conexion->query($consulta) or exit($conexion->error);
  19.  
  20. if ($resultados->num_rows){
  21. ?>
  22.     <select class="combo">
  23. <?php
  24.     while($registros = $resultados->fetch_assoc()){
  25. ?>
  26.         <option value="<?=$registro[$campoCodigo]?>"><?=$registro[$campoNombre]?></option>
  27. <?php
  28.     }
  29.     $resultados->free();
  30. ?>
  31.     </select>
  32. <?php
  33. }
  34.  
  35. $conexion->close();

4. Para que el primer <select> aparezca luego de haber cargado la página, necesitas hacer la llamada a la función ajax() pasándole los respectivos valores. Esto se ejecutará luego de ocurrido el evento DOMContentLoaded el cual se dispara cuando han terminado de cargar los elementos del documento:
Código Javascript:
Ver original
  1. document.addEventListener("DOMContentLoaded", function(){
  2.     ajax({
  3.         nivel: 1,
  4.         seccion: document.querySelector("#ejemplo section") //Por defecto, toma a la primera
  5.     });
  6. }, false);

5. Para realizar las llamadas por cada vez que se elija un valor en cualquiera de los <select> y ya que estos cargarán de manera dinámica, debes asociar el evento change al documento, de tal forma que al ocurrir, tomas al elemento en el cual se produjo el evento y podrás enviar los datos que le correspondan:
Código Javascript:
Ver original
  1. document.addEventListener("change", function(event){
  2.     if (event.target.className == "combo"){
  3.         ajax({
  4.             nivel: [].indexOf.call(document.querySelectorAll(".combo"), event.target) + 1,
  5.             seccion: event.target.parentNode,
  6.             valor: event.target.value
  7.         });
  8.     }
  9. }, false);

6. Cuando ya tengas a los tres <select> y hayas seleccionado las respectivas opciones, puedes proceder a realizar el redireccionamiento, para lo cual tendrás que cancelar el evento submit el cual ocurre cuando se inicia el envío de los datos del formulario. Para esto, deberás utilizar el método .preventDefault():
Código Javascript:
Ver original
  1. document.querySelector("#ejemplo").addEventListener("submit", function(event){
  2.     event.preventDefault(); //Cancelamos el envío
  3.  
  4.     var combos = document.querySelectorAll(".combo"),
  5.         direccion = "http://www.ejemplo.com/" + combos[0].value + "/" + combos[1].value + "/" + combos[2].value;
  6.  
  7.     location = direccion;
  8. }, false);

Todo el código JavaScript debe quedar junto y en el orden descrito, es decir:
Código Javascript:
Ver original
  1. document.addEventListener("DOMContentLoaded", function(){
  2.     //Punto 2
  3.     //Punto 4 (solo la llamada a la función)
  4.     //Punto 5
  5.     //Punto 6
  6. }, false);

En resumen, tenemos tres secciones dentro del formulario en las que cargarán los tres <select>. Al terminar de cargar la página, se llamará a la función ajax() a la cual se le pasarán los valores del nivel (número de <select>) y la sección en la cual aparecerá. Dichos datos se pasan a la función a través de un objeto literal. En la función, se crea una instancia del objeto XMLHttpRequest para realizar la petición asíncrona (AJAX), se reciben los valores y si se ha recibido el valor a tratar en la condición de la consulta a la base de datos, se lo adhiere a cadena de consulta y la ruta del archivo PHP. Se realiza el envío y cuando se reciba la respuesta, se la mostrará en la sección que se haya designado.

En el archivo PHP, se realiza la conexión a la base de datos, se verifica si no se realizó para terminar la ejecución del script y se reciben y limpian los datos recibidos. Así como en la función ajax(), se verifica si se recibió el valor para la condición de la consulta SQL. Enseguida, se procede a elaborar la consulta, se la ejecuta y si se obtienen resultados, se procede a crear al respectivo <select>, el cual tendrá por clase el valor "combo" y se le asignarán las opciones según los registros obtenidos de la consulta a la base de datos. Finalmente, dicho <select> será la respuesta que recibirá la función ajax() y que mostrará en la sección respectiva.

Para este ejemplo, he supuesto que los nombres de las tablas de la base de datos tienen la forma "tabla", seguido del número de tabla según corresponde a cada <select>, esto con el fin de reutilizar el mismo script para realizar distintas consultas a la base de datos, por lo que si los nombres de tus tablas no tienen una forma similar, te sugiero hacerlo de un modo parecido o quizá de otra forma que creas conveniente pero que se adapte al algoritmo propuesto. También puedes tener distintos archivos PHP para elaborar cada <select>, pero sería algo poco eficiente y elegante. Si deseas, puedes utilizar una clase para el tratamiento de los datos en el lado del servidor; por ejemplo, una clase con un método para realizar la conexión, otro para limpiar a los datos recibidos, otra para armar la consulta SQL, otra para ejecutarla, y así.

La delegación del evento change al documento se debe a que no puedes registrar un evento a un elemento que ha cargado después de que haya cargado el documento, como ocurre en los casos de los <select> y otros elementos cargados dinámicamente, por lo que utilizar una clase en común, puede ser de mucha ayuda, como en este caso.

Para obtener al elemento en el que ocurrió el evento, debes acceder a él mediante la propiedad target del objeto del evento. Para obtener a la sección que contiene al <select> en el cual se ha cambiado el valor, debes acceder a ella mediante la propiedad parentNode. Para obtener al nivel, es decir, el número de <select> en el cual ha ocurrido el cambio de valor, debes utilizar una instancia del método .indexOf(), el cual devuelve la posición del elemento en cuestión dentro de —en este caso— la lista de nodos cuya clase es "combo", empezando desde la posición cero, razón por la cual le sumo 1. La lista de nodos es devuelta por el método .querySelectorAll().

Como se trata de un ejemplo, tienes que adaptarlo a lo que necesitas. Si tienes alguna duda, coméntala por aquí.

TIP DE AYUDA: Si quieres utilizar otro valor para los <select> que no sea el valor que estos toman de la opción seleccionada, puedes utilizar atributos personalizados.

Un saludo
__________________
«Juro por mi vida y mi amor por ella, que jamás viviré para el provecho de otro hombre, ni le pediré a otro hombre que viva para el mío».

Ayn Rand

Última edición por Alexis88; 18/01/2016 a las 10:17 Razón: Mensaje de error de conexión