Foros del Web » Programando para Internet » PHP »

[SOLUCIONADO] ¿Evitar fin de petición asíncrona al hacer echo?

Estas en el tema de ¿Evitar fin de petición asíncrona al hacer echo? en el foro de PHP en Foros del Web. Hola! Pues bien, estuve haciendo pruebas con selects dependientes en AJAX y PHP. Me salió esto . Se ve bonito, ..., por fuera. Por dentro, ...
  #1 (permalink)  
Antiguo 26/06/2015, 21:03
Avatar de berkeleyPunk  
Fecha de Ingreso: febrero-2013
Ubicación: México :C
Mensajes: 565
Antigüedad: 11 años, 2 meses
Puntos: 22
Pregunta ¿Evitar fin de petición asíncrona al hacer echo?

Hola!

Pues bien, estuve haciendo pruebas con selects dependientes en AJAX y PHP. Me salió esto.

Se ve bonito, ..., por fuera. Por dentro, puede mejorarse, sin duda.

Son 3 selects. Básicamente hago 3 condicionales que checan qué ha elegido el usuario. Es decir, si acaba de elgir continente, país o provincia. El script que se ejecuta al elegir país añade sólo unas líneas al script de continente. Y el script que se ejecuta al elegir provincia añade sólo unas líneas más al de país. La cosa es que hay código repetido, y no veo la forma de evitar repetirlo.

¿Es posible eliminar los 3 condicionales, de forma que sólo haya un bloque de líneas (que no se repitan ) que devuelvan tal o cual respuesta según la elección del usuario?

Porque, digamos, elijo el continente americano. La respuesta asíncrona me devuelve los países de este continente mediante un echo, y con este echo se termina la petición. Así, no tengo forma de hacer nada más, digamos otro bucle (o lo que sea) para llenar el select de provincias, si es que el usuario eligió un país en vez de un continente. No busco evitar que termine la petición al hacer echo (entiendo que eso no se puede), la idea es no repetir código. Pero el echo no me deja!


Código PHP:
if ( ($continente!="NULL") && ($pais=="NULL") ) {
    foreach (
$arrayPaises as $claveContinente=>$paises) {
        if(
$claveContinente == $continente) {
            foreach(
$paises as $clavePais=>$provincias) {
                
$htmlPais .= '<option id="'.$clavePais.'" value="'.$clavePais.'">'.$clavePais.'</option>';
            }
            
$arrayRespuestas = array (
                
"htmlPais" => $htmlPais,
                
"statusAPP" => "Respuesta AJAX ok para paises"
            
);
            break;
        }
    }
    echo 
json_encode($arrayRespuestas);
}

else if ( (
$continente!="NULL") && ($pais!="NULL") && ($provincia=="NULL")  ) {
    foreach (
$arrayPaises as $claveContinente=>$paises) {
        if(
$claveContinente == $continente) {
            foreach(
$paises as $clavePais=>$provincias) {
                
$htmlPais .= '<option id="'.$clavePais.'" value="'.$clavePais.'">'.$clavePais.'</option>';
            }
            foreach(
$paises as $clavePais=>$provincias) {
                if( 
$clavePais == $pais) {
                    foreach(
$provincias as $claveProvincia=>$city) {
                        
$htmlProvincia .= '<option id="'.$city.'" value="'.$city.'">'.$city.'</option>';
                    }
                    
$arrayRespuestas = array (
                        
"paisElegido" => $pais,
                        
"htmlPais" => $htmlPais,
                        
"htmlProvincia" => $htmlProvincia,
                        
"statusAPP" => "Respuesta AJAX ok para ciudades"
                    
);
                    break;
                }
            }
            break;
        }
    }
    echo 
json_encode($arrayRespuestas);
}


else if ( (
$continente!="NULL") && ($pais!="NULL") && ($provincia!="NULL") ) {
    foreach (
$arrayPaises as $claveContinente=>$paises) {
        if(
$claveContinente == $continente) {
            foreach(
$paises as $clavePais=>$provincias) {
                
$htmlPais .= '<option id="'.$clavePais.'" value="'.$clavePais.'">'.$clavePais.'</option>';
            }
            foreach(
$paises as $clavePais=>$provincias) {
                if( 
$clavePais == $pais) {
                    foreach(
$provincias as $claveProvincia=>$city) {
                        
$htmlProvincia .= '<option id="'.$city.'" value="'.$city.'">'.$city.'</option>';
                        if (
$city == $provincia) {
                            
$ciudadElegida $city;
                        }
                    }
                    
$arrayRespuestas = array (
                        
"provinciaElegida" => $ciudadElegida,
                        
"paisElegido" => $pais,
                        
"htmlPais" => $htmlPais,
                        
"htmlProvincia" => $htmlProvincia,
                        
"statusAPP" => "Respuesta AJAX ok para ciudades"
                    
);
                    break;
                }
            }
            break;
        }
    }
    echo 
json_encode($arrayRespuestas);

Saludos!

Última edición por berkeleyPunk; 26/06/2015 a las 21:10
  #2 (permalink)  
Antiguo 28/06/2015, 13:48
Avatar de NSD
NSD
Colaborador
 
Fecha de Ingreso: mayo-2012
Ubicación: Somewhere
Mensajes: 1.332
Antigüedad: 11 años, 11 meses
Puntos: 320
Respuesta: ¿Evitar fin de petición asíncrona al hacer echo?

Pppfff este tema ya se trato tantas veces.

index.html
Código HTML:
Ver original
  1. <!DOCTYPE html>
  2.  <html>
  3.      <head>
  4.          <title>SELECT DEPENDIENTES</title>
  5.      </head>
  6.      <body>
  7.          <form id="form-depend">
  8.              <select name="continente" data-load="continente">
  9.                 <option value="" class="default">Seleccione</option>
  10.              </select>
  11.  
  12.              <select name="pais" data-load="pais" data-depend="continente">
  13.                 <option value="" class="default">Seleccione</option>
  14.              </select>
  15.  
  16.              <select name="provincia" data-load="provincia" data-depend="continente,pais">
  17.                 <option value="" class="default">Seleccione</option>
  18.              </select>
  19.          </form>
  20.  
  21.          <script>
  22.             function depend(form) {
  23.                 this.form = form;
  24.                 this.init();
  25.             }
  26.             depend.prototype = {
  27.                 "init" : function() {
  28.                     var dependents = this.form.querySelectorAll("select[data-depend]"),
  29.                         standalone = this.form.querySelectorAll("select:not([data-depend])"),
  30.                         dependent;
  31.  
  32.                     for (var d=0; d<dependents.length; d++) {
  33.                        dependent = dependents[d];
  34.                        var mains = this.form.querySelectorAll("[name='" + dependent.dataset.depend.split(",").join("'],[name='") +"']");
  35.                        for (var m=0; m<mains.length; m++)
  36.                            mains[m].addEventListener("change", this.load.bind(this, dependent));
  37.                    }
  38.                    
  39.                    for (var s=0; s<standalone.length; s++)
  40.                        this.load(standalone.item(s));  
  41.                },
  42.                "load" : function(select) {
  43.                    var options = select.querySelectorAll("option:not(.default)");
  44.                    for (var o=0; o<options.length; o++)
  45.                        select.removeChild(options.item(o));
  46.  
  47.                    this.ajax("combo/" + select.dataset.load + ".php", {
  48.                        "success" : function(data) {                            
  49.                            data.forEach(function(item){
  50.                                var option = document.createElement("option");
  51.                                option.value = item.value;
  52.                                option.label = item.label;
  53.                                select.appendChild(option);
  54.                            });
  55.                        },
  56.                        "error" : function(e) {
  57.                            console.log(e);
  58.                            alert(e);
  59.                        }
  60.                    });
  61.                },
  62.                "ajax" : function(url, callbacks) {
  63.                    var request = new XMLHttpRequest();
  64.                    request.open("post", url);
  65.                    request.onreadystatechange = function(callbacks) {
  66.                        if(this.readyState === 4) {
  67.                            var response = this.responseText,
  68.                                success = false;
  69.  
  70.                            if(this.status == 200) {
  71.                                try {
  72.                                    response = JSON.parse(response);
  73.                                    success = true;
  74.                                } catch(e) { }
  75.                            }
  76.  
  77.                            if(success)
  78.                                if(callbacks.success)
  79.                                    callbacks.success(response);
  80.                            else if(callbacks.error)
  81.                                callbacks.error({"response" : response});
  82.                        }
  83.                    }.bind(request, callbacks);
  84.                    request.send(new FormData(this.form));
  85.                }
  86.            }
  87.  
  88.            new depend(document.getElementById("form-depend"));
  89.         </script>
  90.      </body>
  91.  </html>

combo/continente.php
Código PHP:
Ver original
  1. <?php
  2.     $continentes = [
  3.         ["label" => "America", "value" => 1],
  4.         ["label" => "Europa", "value" => 2],
  5.         // ...
  6.     ];
  7.    
  8.     echo json_encode($continentes);

combo/pais.php
Código PHP:
Ver original
  1. <?php
  2.     $paises = [
  3.         1 => [
  4.             ["label" => "Argentina", "value" => 1],
  5.             ["label" => "Uruguay", "value" => 2]
  6.             // ...
  7.         ],
  8.         2 => [
  9.             ["label" => "España", "value" => 3],
  10.             ["label" => "Alemania", "value" => 4]
  11.             // ...
  12.         ],
  13.         // ...
  14.     ];
  15.    
  16.     echo json_encode(empty($paises[$_POST["continente"]]) ? [] : $paises[$_POST["continente"]]);

combo/provincia.php
Código PHP:
Ver original
  1. <?php
  2.     $provincias = [
  3.         1 => [
  4.             ["label" => "Buenos Aires", "value" => 1],
  5.             // ...
  6.         ],
  7.         2 => [
  8.             ["label" => "Montevideo", "value" => 3],
  9.             // ...
  10.         ],
  11.         3 => [
  12.             ["label" => "Madrid", "value" => 4],
  13.             // ...
  14.         ],
  15.         4 => [
  16.             ["label" => "Berlin", "value" => 5],
  17.             // ...
  18.         ],
  19.         // ...
  20.     ];
  21.    
  22.     echo json_encode(empty($provincias[$_POST["pais"]]) ? [] : $provincias[$_POST["pais"]]);
__________________
Maratón de desafíos PHP Junio - Agosto 2015 en FDW | Reglamento - Desafios
  #3 (permalink)  
Antiguo 29/06/2015, 05:54
Avatar de berkeleyPunk  
Fecha de Ingreso: febrero-2013
Ubicación: México :C
Mensajes: 565
Antigüedad: 11 años, 2 meses
Puntos: 22
De acuerdo Respuesta: ¿Evitar fin de petición asíncrona al hacer echo?

Cita:
Iniciado por NSD Ver Mensaje
Pppfff este tema ya se trato tantas veces...
Bueno, pues el código que propones está muy bueno..., pero es un planteamiento absolutamente distinto!

De todas formas, aprendo de él. Gracias NSD!
  #4 (permalink)  
Antiguo 29/06/2015, 09:05
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 16 años
Puntos: 2534
Respuesta: ¿Evitar fin de petición asíncrona al hacer echo?

Cita:
Iniciado por berkeleyPunk Ver Mensaje
Bueno, pues el código que propones está muy bueno..., pero es un planteamiento absolutamente distinto!

De todas formas, aprendo de él. Gracias NSD!
¿Por qué es distinto?

¿Porque imprimes HTML en lugar de devolver los datos?

¿Y si en ese caso tienes una función genérica que tome esos datos y genere el HTML?

Creo que estás pidiendo que alguien piense por ti, cuando bien podrías mejorar la implementación a tu gusto.
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #5 (permalink)  
Antiguo 29/06/2015, 09:24
Avatar de NSD
NSD
Colaborador
 
Fecha de Ingreso: mayo-2012
Ubicación: Somewhere
Mensajes: 1.332
Antigüedad: 11 años, 11 meses
Puntos: 320
Respuesta: ¿Evitar fin de petición asíncrona al hacer echo?

La diferencia mas grande es que no use JQuery y el script completo tiene menos lineas que la configuración usando ese framework

Al margen de eso, otra posible diferencia es que tienes 3 archivos php, pero tranquilamente puedes fusionarlos en uno solo, si le pones el data-load igual a los 3 combos, puedes tener todo en un solo archivo usando ifs tal como lo haces en tu script original.

Otra cosa que puedes mejorar es esta parte:
Código Javascript:
Ver original
  1. data.forEach(function(item){
  2.   var option = document.createElement("option");
  3.   option.value = item.value;
  4.   option.label = item.label;
  5.   if(item.selected)
  6.     option.selected = true;
  7.   select.appendChild(option);
  8. });

Asi puedes enviar una opcion seleccionada por defecto para cada combo.

En fin, coincido con @pateketrueke puedes adaptarlo sin problemas.
__________________
Maratón de desafíos PHP Junio - Agosto 2015 en FDW | Reglamento - Desafios
  #6 (permalink)  
Antiguo 12/07/2015, 20:07
Avatar de berkeleyPunk  
Fecha de Ingreso: febrero-2013
Ubicación: México :C
Mensajes: 565
Antigüedad: 11 años, 2 meses
Puntos: 22
De acuerdo Respuesta: ¿Evitar fin de petición asíncrona al hacer echo?

Perdón por la tardanza...
pateketrueke, buen día. No quiero que alguien piense por mí, generalmente no soy de ese tipo (a veces sí, pero son pocas y no es esta una de esas veces). Quizá me expresé mal, quizá tú le encontraste el lado negativo, flojo, a mi comentario. Llegué aquí inicialmente pidiendo ayuda en el sentido de que se me diera una idea, un camino, una ruta sobre cómo modificar el script para hacer una función genérica para los selects dependientes. Algo como: "Mira, yo haría una función con 3 parámetros, uno que indicara qué select ha sido elegido, otro...". Eso es todo.

Comencé ya con dicha función, a ver qué tal me sale. Cuando tenga avances importantes, y desde luego los problemas que no pueda solucionar, regreso.

Saludos!
  #7 (permalink)  
Antiguo 16/08/2015, 17:13
Avatar de berkeleyPunk  
Fecha de Ingreso: febrero-2013
Ubicación: México :C
Mensajes: 565
Antigüedad: 11 años, 2 meses
Puntos: 22
Respuesta: ¿Evitar fin de petición asíncrona al hacer echo?

Tarde pero seguro!

Rehice una buena parte del código. No pude hacer una función genérica que devolviera el contenido para cada select. Sin embargo, todo quedó mejor. Cambié un par de cosas en atención al script de NSD. Este par de cosas fueron:

1) ya no uso un solo array con toda la información de continentes, países y provincias. Esto me obligaba a que cada vez que elegía una opción de un select, tener que ejecutar un foreach que leyera ese array desde el principio. Así que,
2) dividí ese array en 3 (continentes, países y provincias).

Código PHP:
$arrayPaises = array(
    
"africa" => array(
        
"Sudáfrica",
        
"Etiopía",
        
"Marruecos",
        
"Senegal",
        
"Gana"
    
),
...
);

foreach(
$arrayPaises as $continente=>$listaPaises) {
    if(
$valorSelectElegido == $continente) {
        foreach(
$listaPaises as $clavePais=>$pais) {
            
$htmlPais .= '<option>'.$pais.'</option>';
        }
        ...
    }

De esta forma me ahorro, en este caso, el bucle sobre los continentes.

Hice otras mejoras, pero acerca del problema que plantee originalmente, esto fue lo más que pude hacer.

Saludos!

Etiquetas: Ninguno
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 02:43.