13

Esto es difícil de articular y soy nuevo en el desarrollo web móvil así que tenga paciencia conmigo:Comportamiento extraño de on/dropdown onchange() Evento JS al utilizar 'Siguiente' en Mobile Safari Lista desplegable seleccionar elemento

En mi página web, Tengo 3 listas desplegables anidadas (Área, Pueblo, Calle).

Anidado como en, los elementos de cada menú desplegable se modifican cuando cambia la selección en el menú desplegable situado encima. por ejemplo la selección de un área de cambia la Ciudad y Calle listas y selección de una ciudad cambia la lista la calle.

Utilizo XMLHTTPRequests en el evento onchange() javascript de las listas desplegables para recuperar y rellenar las otras downdowns. Esto funciona bien en los navegadores Android y de escritorio.

En Mobile Safari, cuando se toca un drowdown, se muestra una lista donde el usuario puede seleccionar elementos. Además, el cuadro de selección tiene los botones "Anterior/Siguiente/Autorrelleno/Hecho" para desplazarse a otros elementos del formulario.

De modo que el usuario toca el primer menú desplegable, selecciona un valor y presiona el botón Siguiente. Esto causa dos problemas:

Primero, en esta acción, el primer evento oncange() desplegable no se desencadena de forma confiable. A veces se dispara a veces no.

Si después de seleccionar un Área, el usuario toca en otro lugar en la página web o presiona el botón "Hecho", el cambio() se dispara normalmente y los Pueblos y Calles se llenan normalmente.

Segundo elemento, el elemento que se enfoca cuando se presiona el botón "Siguiente" es el menú desplegable que necesita cambiar los elementos después de la búsqueda. Cuando se activa el onchange() del menú desplegable anterior, o bien la lista no se actualiza o los elementos en el cuadro de selección se vuelven azules y todos tienen una marca que muestra que todos están seleccionados ..

De Lo que sí puedo decir es que el problema se resolverá si puedo desactivar los botones Siguiente/Anterior en el cuadro de selección o arreglar de algún modo cómo se activa el cambio() y los elementos de la lista desplegable siguiente se vuelven a llenar mientras está enfocado.

Aquí está el código (simplificado):

<!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> 
    <meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=no" /> 

    <title></title> 
</head> 
<body onload="AppStart();"> 
    <form action="#"> 
    Area: 
    <select id="ddlArea"> 
     <option value="">-- Select Area -- </option> 
     <option value="1">Area 1</option> 
     <option value="2">Area 2</option> 
     <option value="3">Area 3</option> 
     <option value="4">Area 4</option> 
     <option value="5">Area 5</option> 
    </select> 
    <br /> 
    Town: 
    <select id="ddlTown"> 
     <option value="">Please wait ...</option> 
    </select> 
    <br /> 
    Street: 
    <select id="ddlStreet"> 
     <option value="">-- Select Area or Town -- </option> 
    </select> 
    <br /> 
    Unit: 
    <select id="ddlUnit"> 
     <option value="">-- No Street Selected -- </option> 
    </select> 

    <script type="text/javascript"> 

     var ddlArea, ddlTown, ddlStreet, ddlUnit; 
     function AppStart() { 
      ddlArea = document.getElementById("ddlArea"); 
      ddlTown = document.getElementById("ddlTown"); 
      ddlStreet = document.getElementById("ddlStreet"); 
      ddlUnit = document.getElementById("ddlUnit"); 

      ddlArea.onchange = areaChanged; 
      ddlTown.onchange = townChanged; 
      ddlStreet.onchange = streetChanged; 

      setTimeout(function() { updateTown(""); }, 250); 
     } 

     var areaId = "", townId = "", streetId = "", unitId = ""; 
     function areaChanged(e) { 
      areaId = ddlArea.options[ddlArea.selectedIndex].value 
      ddlClear(ddlTown, createOption("Please Wait...", "")); 
      ddlClear(ddlStreet, createOption("Please Wait...", "")); 
      ddlClear(ddlUnit, createOption("-- No Street Selected --", "")); 
      setTimeout(function() { updateTown(areaId); }, 500); 
      setTimeout(function() { updateStreet(areaId, ""); }, 700); 
     } 

     function townChanged(e) { 
      townId = ddlTown.options[ddlTown.selectedIndex].value 
      ddlClear(ddlStreet, createOption("Please Wait...", "")); 
      ddlClear(ddlUnit, createOption("-- No Street Selected --", "")); 
      setTimeout(function() { updateStreet(areaId, townId); }, 400); 
     } 

     function streetChanged(e) { 
      streetId = ddlStreet.options[ddlStreet.selectedIndex].value 
      ddlClear(ddlUnit, createOption("Please Wait...", "")); 
      setTimeout(function() { updateUnit(streetId); }, 600); 
     } 

     function updateTown(areaID) { 
      ddlClear(ddlTown, createOption("-- Select Town --", "")); 
      var items = isNaN(parseInt(areaID)) ? 10 : parseInt(areaID); 
      if (areaID == "") areaID = "ALL"; 
      for (var i = 0; i < items; i++) { 
       ddlTown.appendChild(createOption("Town " + (i+1) + ", Area " + areaID, i)); 
      } 
     } 

     function updateStreet(areaID, townID) { 
      ddlClear(ddlStreet, createOption("-- Select Street --", "")); 
      var items1 = isNaN(parseInt(areaID)) ? 10 : parseInt(areaID); 
      var items2 = isNaN(parseInt(townID)) ? 10 : parseInt(townID); 
      var items = items1 + items2; 
      if (areaID == "") areaID = "ALL"; 
      if (townID = "") townId = "ALL"; 
      for (var i = 0; i < items; i++) { 
       ddlStreet.appendChild(createOption("Street " + (i + 1) + ", Area " + areaID + ", Town " + townID, i)); 
      } 
     } 

     function updateUnit(streetID) { 
      ddlClear(ddlUnit, createOption("-- Select Unit --", "")); 
      var items = isNaN(parseInt(streetID)) ? 10 : parseInt(streetID); 
      if (streetID == "") streetID = "ALL"; 
      for (var i = 0; i < items; i++) { 
       ddlUnit.appendChild(createOption("Unit " + (i + 1) + ", Street " + streetID, i)); 
      } 
     } 

     function ddlClear(Dropdown, option) { 
      while (Dropdown.options.length > 0) { 
       try { Dropdown.options[0] = null; } catch (e) { }; 
      } 
      if (option != null) { 
       Dropdown.appendChild(option); 
      } 
     } 

     function createOption(text, value) { 
      var oOption = document.createElement("OPTION"); 
      oOption.innerHTML = text; 
      oOption.value = value; 
      return oOption; 
     } 

    </script> 

    </form> 
</body> 
</html> 

Ayuda. :/

Respuesta

28

Tuve el mismo problema en mi sitio. Pude solucionarlo consultando manualmente la propiedad selectedIndex en el control de selección. De esta forma, se activará tan pronto como "verifique" el elemento en la lista. Aquí es un plugin de jQuery que escribí para hacer esto:

$.fn.quickChange = function(handler) { 
    return this.each(function() { 
     var self = this; 
     self.qcindex = self.selectedIndex; 
     var interval; 
     function handleChange() { 
      if (self.selectedIndex != self.qcindex) { 
       self.qcindex = self.selectedIndex; 
       handler.apply(self); 
      } 
     } 
     $(self).focus(function() { 
      interval = setInterval(handleChange, 100); 
     }).blur(function() { window.clearInterval(interval); }) 
     .change(handleChange); //also wire the change event in case the interval technique isn't supported (chrome on android) 
    }); 
}; 

Se utiliza al igual que lo haría con el evento "cambio".Por ejemplo:

$("#mySelect1").quickChange(function() { 
    var currVal = $(this).val(); 
    //populate mySelect2 
}); 

Editar: Android no enfocar la selección cuando se toca para seleccionar un nuevo valor, pero también no tiene el mismo problema que hace iPhone. Así que corrige al cablear también el antiguo evento change.

+0

Gracias por esto .. He resuelto este problema llamando a blur() en el siguiente menú desplegable, cuando se cambió la primera selección y se devolvieron los datos de XMLHttpRequest, por lo que el cuadro de selección desapareció y el usuario tuvo que tocar el segundo menú desplegable para acceder a él, que hace que los elementos se actualicen en la lista ... fue un truco que no me gusta mucho ... –

+0

Esta es una gran solución que resolvió la falla de primer orden del navegador web Safari Mobile (que es todavía presente en iOS 5). Pero parece haber dejado otro efecto secundario. Ahora el "spinner" está poblando, pero al presionar "next" o "done" el pulldown actual no parece actualizarse con la selección y no se registra. ¿Alguna idea? Además, la solución parecía romper temporalmente la versión de la interfaz de Android. Pero luego funcionó. – iJames

+0

Descubrí el problema de Android después de publicar esto. Ver mi edición y el nuevo código anterior para la solución. ¿Puedes crear un jsfiddle para el primer problema? – InvisibleBacon

Cuestiones relacionadas