jQuery Mobile: Poniendo Javascript a las páginas

Como jQuery Mobile utiliza un sistema de navegación controlado por Ajax, hay una serie de cosas que debes saber cuando manipulas el contenido del HTML con Javascript.

1.Scripts & styles en el head

Cuando un usuario hace click en una web conducida por jQuery Mobile, el comportamiento por defecto del sistema de navegación es utilizar el href del link para hacer una petición de request de Ajax (en vez de de permitir el comportamiento por defecto del navegador de hacer una request de la página completa).Cuando la request Ajax finaliza, el framework recibirá el contenido de texto completo, pero sólo inyectará los contenidos del elemento body de la respuesta (o más especificamente el elemento que tenga “data-role=’page'”, si viene alguno), lo que quiere decir que nada de lo que vaya en el head de la página será utilizado (con la excepción del title, que es recuperado especificamente).

Esto quiere decir que cualquier script y estilo referenciado en el head de la página on tendrá ningún efecto cuando un page es cargada via Ajax, pero se ejecutará si la página es pedida normalmente por HTTP. Cuando se quiere hacer scripting de webs con jQuery Mobile, ambos escenarios deben ser considerados. La razón de que el head sea ignorado cuando se hace la petición Ajax es que el potencial de re-ejecutar el mismo Javascript es muy alto (es muy habitual referenciar los mismos scripts en todas las páginas del site). Debido a la complejidad de intentar trabajar para sobrellevar esta situación, dejamos la tarea de ejecutar scripts especificos de page al programador, y asumimos que los scripts que van en el head son sólo ejecutados una vez por sesión del usuario.

La aproximación más simple cuando se construye una web con jQuery Mobile es referenciar el mismo conjunto de stylesheets y scripts en el head de todas las páginas. Si necesitas cargar scripts específicos para una página en particular, recomendamos enlazar la lógica que necesitemos al evento ‘pagecreate‘ para ejecutar el código necesario cuando una página específica es creada (que puede ser determinado por el atributo id, o por otras formas). Siguiendo esta aproximación aseguraremos que el código se ejecuta si la página es cargada directamente o es invocada por medio de Ajax.

Otra aproximación para page-specific scripting sería incluir scripts al final del elemento body. Si incluyes tu custom scripting de esta forma, ten cuidado que estos scripts se ejecuten cuando la página se cargue por Ajax o por HTTP regular, asi estos scripts son los mismos en todas las páginas y esto puede llevar a problemas. Incluyendo scripts de esta forma, recomendariamos encerrar el contenido de la página en un elemento “data-role=’page'”, y colocar los scripts que son referenciados en todas las páginas fuera de este elemento. Los scripts que son únicos a la página pueden ser colocados dentro de ese elemento, para asegurar que se ejecuten cuando la página es cargada via Ajax.

 

2.En jQuery Mobile tenemos que pagecreate = DOM ready

Una de las primeras cosas que la gente aprende en jQuery es utilizar la función $(document).ready() para ejecutar código DOM-specific tan pronto como el DOM esta listo (lo cual ocurre mucho antes del evento onload). Sin embargo, en las webs y aplicaciones hechas con jQuery Mobile, las pages son pedidas e inyectadas en el mismo DOM según el usuario navega, de forma que los evento DOM ready no son útiles, ya que solo se ejecutan con la primera página. Para ejecutar código cuando quiera que una página es cargada y creada en jQuery Mobile, debes enlazar con el evento pagecreate.

El evento pagecreate es disparado en una página cuando es inicializada, justo después de que ocurre la inicialización. La mayoria de los widgets oficiales de jQuery Mobile se autoinicializan ellos mismos basados en este evento, y por tanto es bueno que tu configures tu código basandose en este evento.

[codebox 1]

Si te gusta manipular los contenidos de una page antes de que se dispare el evento pagecreate y los widgets se autoinicialicen, puedes enlazar con el evento pagebeforecreate:

[codebox 2]

3.Cambiando de página

Si quieres cambiar la página activa actual con Javascript, puedes utilizar el método changePage. Hay muchos métodos y properties que pueden ser configurados en los cambios de pages, vemos aqui dos ejemplos:

[codebox 3]

4.Carga de páginas

Para cargar una página externa, ampliar su contenido e insertarlo en el DOM, podemos utilizar el método loadPage.Hay muchos métodos y propoerties que pueden configurar cuando cargas páginas. Veamos un ejemplo simple:

[codebox 4]

5.Incluyendo maquetación nueva

El plugin page dispara un evento pagecreate , que la mayoria de los widgets lo utilizan para autoinicializarse. Tan pronto como un script plugin de widget es referenciado, automáticamente amplia cualquier instancia de widget que encuentre en la página.

Sin embargo, si generamos una nueva maquetación del lado del cleinte o cargamos el contenido via Ajax y lo inyectamos dentro de una page, puedes disparar el evento create para manejar la autoinicialización de todos los plugins contenidos dentro de la nueva maquetación. Esto puede ser disparado sobre cualquier elemento (incluso el page div en si mismo), diciendote la tarea para inicializar manualmente cada plugin (listview button, select, etc).

Por ejemplo, si un bloque de maqueta HTML (por ejemplo un formulario de login) ha sido cargado via Ajax, entonces se dispara el evento create para automaticamente transformar todos los widgets que contiene (inputs y buttons en este caso) en sus versiones ampliadas. El código para este escenario sería:

[codebox 5]

6.Create vs. refresh: in distinción importante

Vemos que hay una importante diferencia entre el evento create y el método refresh que algunos widgets tienen. El evento create esta hecho para ampliar nueva maquetación ‘cruda’ que contiene uno o más widgets.El método refresh deberia ser utilizado en widgets ya existentes (ya ampliados) que han sido manipulados programaticamente y necesitan que el UI se actualice.

Por ejemplo, si tuvieramos una page donde dinamicamente añadimos una nueva lista no ordenada con el atributo data-role=listview despues de la creación de la página, disparar el evento create sobre un elemento parent de esa lista la transformaría en un widget listview estilizada. Si se van a añadir más elementos de la lista programaticamente, llamar al método refresh del listview actualizará esos nuevo elementos de la lista al estado ampliado y deja los elementos de la lista existentes sin tocar.

7. Hacer scroll a una position dentro de una page

Ya que estamos utilizando la URL hash para conservar el comportamiento del Back button, utilizar page anchors para saltar a una posición dentro de la misma page no es soportada utilizando el anchor link tradicional (#foo). Utilizamos el método silentScroll para hacer scroll a una posición Y en particular sin la necesidad de disparar scroll event listeners. Ejemplo:

[codebox 6]

NOTA: Si bien , basandome en mi propia experiencia , tengo que decir que no funciona este método en los navegadores de los móviles como Iphone y Android. Entonces he utilizado un método más estandar de jQuery que hace lo mismo y funciona en los navagadores de loss dispositivos:

[codebox 7]

8.Enlazando a eventos de mouse y de touch

Una importante consideración en las plataformas móviles es el manejo de los eventos mouse y touch. Estos eventos difieren significativamente entre diferentes plataformas móviles, pero el denominador común es que los eventos de click funcionan en todas partes, pero generalmente después de un retraso también significativo de entre 500-700 ms. Este retraso es necesario para que el navegador puede esperar por el double tap (toque doble), u otros eventos tap extendidos. Para eliminar este retraso, es posible enlazar estos eventos a eventos touch. El problema con esta aproximación es que las plataformas WP7 y BlackBerry no soportan touch. Para sobrellevar este inconveniente, algunas plataformas emiten por duplicado los eventos de touch y de mouse, asi que si enlazamos con los dos tipos de eventos , para una sola interacción se dispararán dos veces.

Nuestra solución es crear un conjunto de eventos virtuales que normalicen los eventos de touch y de mouse. Esto permite a los programadores registrar listeners para los eventos de mouse básicos, tal como mousedown, mousemove, mouseup y click , y el plugin tendrá cuidado de registrar los listeners correctos por nosotros para invocar al listener en el menor tiempo posible para ese dispositivo en concreto. Esto aún retiene el orden de disparo de los eventos como en el entorno del mouse tradicional, debe registrarse multiples manejadores  en el mismo elemento para cada uno de los eventos.

El sistema virtual de mouse expone los siguientes eventos virtuales para que se enlacen con métodos de jQuery:

vmouseovervmousedownvmousemovevmouseupvclick, and vmousecancel

9.Pasar parámetros entre páginas

jQuery Mobile no soporta el paso de parámetros por la request entre pages internas o embebidas. Por ejemplo, si el framework ve un enlace de la siguiente forma “#somePage?someId=1”

jQuery Mobile does not support query parameter passing to internal/embedded pages. For example, if the framework sees a link to “#somePage?someId=1” it interpret that as “#somePage” and navigate to the internal page div with an ID of somePage and apply a data-url of#somePage?someId=1 to that page container. Subsequent calls to other params such as “#somePage?someId=2” will find the same div because jQuery Mobile refers to the data-url on the div which is only set once and will remain at #somePage?someId=1.

There are two plugins that you can add to your project if query parameters are needed between pages. There is a lightweight page params plugin and a more fully featured jQuery Mobile router plugin for use with backbone.js or spine.js.