En el tutorial anterior aprendimos a crear una interfaz base que usa las pestañas de Jquery UI como navegación y el plugin Jquery Address que permite utilizar los botones del navegador atrás y adelante, compartir la URL, guardarla en favoritos, etc. como hacemos cuando navegamos entre páginas normalmente pero en este caso para la navegación AJAX.
En este nuevo tutorial usaremos objetos en javascript para ordenar el código que se ejecutará entre las acciones de una pestaña u otra.
Asumiremos que cada pestaña es un "Controlador" y dentro de ellas ejecutaremos "Acciones" tal como lo hacemos en Frameworks como Symfony, Codeigniter, etc. Por ejemplo cuando accedemos a noticias/lista, internamente estamos usando el controlador Noticias y la acción "lista". En este caso haremos algo similar pero en javascript.
Modelo Vista Controlador en Javascript
Para empezar podemos descargar el código. Las bibliotecas que usaremos en esta ocasión serán las mismas, sólo que agregué main.js.El archivo main.js contiene algunas funciones / clases en javascript que actuan como un sencillo framework de rutas para permitir el llamado a nuestros controladores / acciones cada vez que cambie el hash URL.
Para ello en nuestro código anterior cambiaremos el contenido de la funcion / callback $.address.change a esto:
Código :
$.address.change(function(event) { App.handleRequest(event, 'ruylopez'); });Como se imaginarán App.handleRequest es el método encargado de manejar la petición o evento (event), el segundo parámetro (en este caso: 'ruylopez') es el controlador que será invocado por defecto.
Ahora cada vez que se cambie la URL el callback $.address.change llamará a App.handleRequest() que se encargará de manejar la petición por nosotros, llamando a los controladores y acciones adecuados; ahora bien, todo lo que resta hacer es... exacto! Escribir los controladores.
Escribiremos un controlador sencillo
Código :
function RuylopezController () { var Ctr = this; this.name = "ruylopez"; this.init = function () { dummy_log ('RuylopezController.init()'); } this.indexAction = function (Request) { // Seleccionamos la pestaña "ruylopez" $("#tabs").tabs("select", Ctr.name); dummy_log ('RuylopezController.indexAction()'); } }
Puntos a destacar:
- Se utiliza una pequeña convención para el nombre del controlador: Primera letra de la URL en mayúscula seguida por la palabra "Controller"
- Dado que en Javascript no tenemos "constructores" como tal, decidí "englobar" el código que debe ejecutarse al cargar el controlador por primera vez en la función "init", escribir esta función es opcional y su código se ejecutará sólo una vez como ya mencioné.
- También podemos usar la función "preExecute" como callback, se ejecutará antes de llamar a una acción, la diferencia con "init" es que "preExecute" si se ejecutará varias veces, una vez por cada llamado a una acción de dicho controlador.
- Las acciones son en minúscula y van seguidas por el sufijo "Action"
- Como se puede ver la opción por defecto es "indexAction" pero se pueden usar otras, como veremos más adelante en este tutorial.
- En Javascript "this" se refiere al objeto que invocó a una función y no necesariamente al objeto o controlador como tal, como sucede en PHP, por esto usamos "var Ctr = this;" cuando querramos referirnos a una propiedad o método del controlador dentro de éste usaremos "Ctr" y no this para evitar errores.
- Podemos declarar las variables y métodos que queramos dentro del controlador.
Manejando URLs más complejas
Ahora, los ejemplos que hemos visto hasta ahora son muy sencillos, supongamos que queremos llamar a una acción más compleja, por ejemplo, dentro de la pestaña "siciliana" queremos analizar la variante del dragon y la variante najdorf, haríamos esto en el HTML:Código :
<h3>Variantes</h3> <ul> <li><a href="#siciliana/dragon">Dragón</a></li> <li><a href="#siciliana/najdorf">Najdorf</a></li> </ul>Ahora cuando alguien haga clic en Najdorf automáticamente se llamaría a SicilianaController.najdorfAction() vamos a agregarlo en el código del ejemplo:
Código :
this.najdorfAction = function (Request) { dummy_log ('SicilianaController.najdorfAction()'); }Y por supuesto haríamos otra acción "dragonAction" para el link a la variante dragón.
Nota :
Pero, ¿Qué pasa si necesitamos parámetros?. Sencillo: supongamos que queremos mostrar links a los ejemplos de la variante najdorf, hacemos esto en el HTML:
Código :
<div id="najdorf"> <h3>Ejemplos variante najdorf: </h3> <ul> <li><a href="#siciliana/ejemplos/variante/najdorf/numero/1">Ejemplo 1</a></li> <li><a href="#siciliana/ejemplos/variante/najdorf/numero/2">Ejemplo 2</a></li> </ul> </div>Noten que estas nuevas URLs siguen el siguiente patrón:
controlador/accion/nombre_parametro_1/valor_parametro_1/.../nombre_parametro_N/valor_parametro_N
Ahora creamos la acción para dichas URLs:
Código :
this.ejemplosAction = function (Request) { var variante = Request.Url.getParam('variante'); var num = Request.Url.getParam('numero'); dummy_log('Ejemplo variante ' + variante + ' numero: ' + num); }Vemos que la función Request.Url.getParam() nos permite obtener el valor del parámetro o parámetros, en este caso "variante" y "numero" y podríamos utilizarlos para las peticiones $.ajax, etc.
Ahora, para mejorar nuestro ejemplo, volveremos atrás y reemplazaremos estas funciones de sicilianaController:
Código :
this.preExecute = function () { $("#tabs").tabs("select", Ctr.name); $('#najdorf').hide(); dummy_log ('SicilianaController.preExecute()'); } this.najdorfAction = function (Request) { dummy_log ('SicilianaController.najdorfAction()'); $('#najdorf').fadeIn(); }Como podemos ver ahora la capa con los ejemplos de la najdorf sólo se mostrará si hacemos click en "Najdorf" mejorando así nuestra interfaz.
Puedes ver el ejemplo funcionando aquí
Otras funciones
Nuestros métodos preExecute y *Action recibirán siempre como parámetro el objeto Request este objeto tiene varios métodos y propiedades útiles:Código :
Request.Url.getUrl() //Obtiene la URL completa Request.Url.getUrlForPag() //Obtiene la URL removiendo la Regex /page/[numero] al final, por ej: noticias/lista/page/5 devolvería: noticias/lista. Request.Url.getModule() //Obtiene el nombre del módulo, por ej "noticias" Request.Url.getAction() //Obtiene el nombre de la acción, por ej "lista" Request.Url.getParams() //Obtiene todos los parametros en un array Request.Url.getParam("param") //Obtiene el valor de un parametro Request.Url.hasParam() //Revisa si un parametro existe App.getCurrentController() //Obtiene el controlador que se esta ejecutando actualmente, o el ultimo en ejecutarse App.getCurrentModule() //Obtiene el nombre del modulo actual App.refresh() //Vuelve a ejecutar la ultima petición invocada App.getController(nombre) //Obtiene un controlador manualmente, util porque esto trabaja como singleton y permite usar "init" adecuadamenteTambién se pueden agregar nuevos métodos o modificar el código a gusto.
Un último detalle ¿Qué pasa con los eventos click, change, etc?
Como estos eventos por lo general no tienen y de hecho no deben tener "hash": no vamos a cambiar la URL por cada acción que haga el usuario, por ejemplo si le da click en "guardar" NO debemos cambiar la URL sólo guardar los datos y ya (si lo estamos haciendo con ajax, por supuesto). Entonces estos eventos los seguiremos haciendo normalmente, por lo general yo lo coloco en la función init() del controlador correspondiente.Código :
this.init = function () { dummy_log ('SicilianaController.init()'); $('#btn_enviar_comentarios').click (function () { Ctr.enviarComentarios(); // << se llama al metodo con el codigo return false; }) } this.enviarComentarios = function () { alert ('abrir modal con form de comentarios'); }Por lo general, como en el ejemplo, creo un método en el mismo controlador, para mantener la lógica y el orden, pero ya queda de parte de cada quien cómo manejar esta parte.
Ver el ejemplo (noten el link al final)
Conclusión
Espero más que darles un código ready-to-use darles una idea de cómo podemos hacer que javascript apeste menos y sea más funcional y reusable y espero que les haya gustado el tutorial.El código sólo lo he probado en Firefox y Chrome hasta ahora por lo que quizás haya que modificar algo para
Puedes descargar el código completo aquí o verlo funcionando
¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.
Por M@U el 06 de Marzo de 2011
Por Duilio el 06 de Marzo de 2011
Por bohorkez el 08 de Marzo de 2011
Muchas gracias...
Por jseros el 11 de Marzo de 2011
Por bkv el 05 de Abril de 2011
Por orochies el 07 de Septiembre de 2011
Por Americo el 08 de Mayo de 2012
Por spaina el 22 de Noviembre de 2012
soy nueva en esto y tengo que desarrollar una aplicación web que use ajax y no encontraba mucha explicación de cómo usarlo con mvc. entonces, para aclararme, usando mvc, las requests de ajax para actualizar, irían en el controlador?
y otra pregunta, por si pueden contestarme, aunque no tiene tanto que ver con esto. creen que es útil usar uwe para modelar en un sistema de arquitectura mvc?
muchísicmas gracias, ando algo perdida en esto.
Por kanfor el 25 de Marzo de 2014
Un par de dudas: los objetos App y Request donde están declarados?
Gracias.
Por kanfor el 25 de Marzo de 2014
Por ra el 23 de Marzo de 2015
Muchas gracias!!
Por Didi el 10 de Junio de 2016
Muchas gracias!!