Este tutorial pertenece a la siguiente serie:
Está dirigido a desarrolladores con experiencia en la creación de aplicaciones web en Java. A continuación aprenderás a manejar los componentes de la vista manualmente e implementar la lógica necesaria para que funcione nuestra aplicación.
A lo largo de este documento hacemos referencias a fuentes externas, las encontrarás todas en la sección de Referencias
El siguiente paso, después de crear el interfaz de usuario, es que esta, responda a la interacción del usuario. Lo que vamos a hacer a continuación es mostrarte cómo controlar por tí mismo los componentes del interfaz de usuario. Este podría estar considerado como el patrón de diseño Modelo-Vista-Controlador (MVC) [2].
El patrón MVC divide la aplicación en 3 partes.
El modelo consta de los datos de la aplicación y las reglas de negocio. La clase CarService y otras clases usadas por ella representan la parte del modelo en nuestra aplicación de ejemplo.
La vista cubre la interfaz de usuario. La página zul que contiene los componentes de ZK representa esta parte. La interacción del usuario con los componentes de la vista genera eventos que son enviados a los controladores.
El controlador juega el rol de coordinador entre la Vista y el Modelo. En esencia, recibe eventos de la vista para actualizar el Modelo y recibe datos del Modelo para cambiar la presentación, es decir la Vista.
En ZK, el controlador es responsable de controlar los componentes de la vista y escuchar y lanzar los eventos que genera la interacción de los usuarios con los mismos. Para crear un controlador simplemente tenemos que extender la clase org.zkoss.zk.SelectorComposer:
package tutorial;
// omit import for brevity
public class SearchController extends SelectorComposer<Component> {
}
Después de crear el controlador, lo asociamos al componente de la vista correspondiente. Asociar un controlador con un componente requiere que indiquemos el nombre completo de la clase en el atributo “apply” en la página zul. A continuación vemos como asociar un controlador a un componente “window” en la vista.
Extraído de searchMvc.zul
<window title="Search" width="600px" border="normal"Puesdes ver el fichero .zul completo en la sección de referencias en el siguiente link [3]
apply="tutorial.SearchController">
<!-- omit other components for brevity -->
</window>
Después de asociar el controlador con el componente “window” de la vista, el controlador puede escuchar los eventos que se generan en la interfaz de usuario, tanto los del componente windows como los de los componentes hijos “child”, y esto nos permite implementar las funciones de la aplicación.
Empecemos con la función de buscar: Un usuario escribe un texto, hace clic sobre el botón “Search” para lanzar la búsqueda.
Pasos para implementar la función necesaria:
Cuando asociamos un controlador a un componente, todos los eventos lanzados por ese componente (y sus componentes hijos “child”) son enviados al controlador. Si hay un método que hemos asignado para recoger el evento será invocado.
Por ejemplo si un usuario hace clic sobre el botón “Search”, para lanzar la función de búsqueda, tenemos que escuchar el evento “onClick”. Declaramos el método “search()”, y lo asociamos al evento lanzado por el botón con la siguiente anotación:
@Listen(“[EVENT_NAME] = #[COMPONENT_ID]”)
Por lo tanto el método con la anotación queda como método “listener”
El código final quedaría como se muestra a continuación:
public class SearchController extends SelectorComposer<Component> {
@Listen("onClick = #searchButton")
public void search(){
}
}
Después de establecer la relación entre el evento de la vista (zul) y el método del “Listener”, podemos empezar a implementar la lógica de negocio. Pero primero tenemos que definir en el controlador, los componentes de los que escuchamos sus eventos mediante la anotación @Wire.
Pasos para recibir eventos de los componentes:
Entonces ZK “conecta” el componente de la vista ZUL a la variable declarada. Después de que esto esté hecho, podemos controlar y manipular el interfaz de usuario directamente manipulando las variables que hemos declarado.
public class SearchController extends SelectorComposer<Component> {
@Wire
private Textbox keywordBox;
@Wire
private Listbox carListbox;
//other codes...
}
El método de la búsqueda contiene una lógica simple: Llama a la clase de servicio “carService” con el texto que buscamos e inserta los resultados en la lista “listbox”. De una variable que está referenciada/unida a un componente, podemos conocer el valor de sus atributos a través de getters (por ejemplo getValue()) o cambiar el estado del componente visual, por ejemplo haciendo un componente de etiqueta “label” invisible mediante un setter (por ejemplo setVisible(false)) para conseguir una respuesta dinámica en el interfaz de usuario.
Por lo tanto, podemos obtener el texto escrito por el usuario mediante “keywordBox.getValue()” y cambiar la información de la lista “listbox” mediante “carListbox.setModel()”. El modelo de un componente es la información que este componente contiene, y podemos cambiar el modelo cambiando los datos directamente en la pantalla.
public class SearchController extends SelectorComposer<Component> {
//omit codes to get components
@Listen("onClick = #searchButton")
public void search(){
String keyword = keywordBox.getValue();
List<Car> result = carService.search(keyword);
carListbox.setModel(new ListModelList<Car>(result));
}
}
Hemos conseguido que se invoque la búsqueda correctamente al hacer clic, pero todavía queremos mostrar en el listbox los resultados de la búsqueda correctamente. Ese es el motivo por el cual no hemos especificado cómo mostrar el modelo de datos en el componente “listbox”. Ahora usaremos una etiqueta de zul especial, “” [7], para controlar lo que mostramos de cada resultado.
ZK mostrará la etiqueta “” iterativamente para cada objeto del modelo, es decir de los resultados.
Pasos para usar “<template>”:
Extraído de searchMvc.zul
<listbox id="carListbox" height="160px" emptyMessage="No car found in the result">
<listhead> <listheader label="Name" /> <listheader label="Company" /> <listheader label="Price" width="20%"/> </listhead>
<template name="model"> <listitem> <listcell label="${each.name}"></listcell> <listcell label="${each.company}"></listcell> <listcell>$<label value="${each.price}" /></listcell> </listitem> </template>
</listbox>
Las secciones anteriores describen los pasos básicos para implementar una función en ZK. Veamos a continuación cómo aplicar todos los pasos aprendidos para implementar la funcinalidad para ver detalles de nuestra aplicación. Declaramos el método para escuchar el evento “onSelect” de la lista “listbox” con la anotación @Listen, entonces usaremos la anotación @Wire para escuchar componentes, incluyendo “previewImage”, “nameLabel”, “priceLabel” y “descriptionLabel” y les asignamos valores con los métodos setter.
public class SearchController extends SelectorComposer<Component> {
@Wire
private Listbox carListbox;
@Wire
private Label nameLabel;
@Wire
private Label companyLabel;
@Wire
private Label priceLabel;
@Wire
private Label descriptionLabel;
@Wire
private Image previewImage;
@Listen("onSelect = #carListbox")
public void showDetail(){
Car selected = carListbox.getSelectedItem().getValue();
previewImage.setSrc(selected.getPreview());
nameLabel.setValue(selected.getName());
companyLabel.setValue(selected.getCompany());
priceLabel.setValue(selected.getPrice().toString());
descriptionLabel.setValue(selected.getDescription());
}
//omit other codes for brevity
}
Para obtener el código fuente completo, por favor mira la sección de referencias [9]
A continuación puedes descargar el código fuente completo de la aplicación de ejemplo, preparado sobre un proyecto de Ecplise que puedes importar directamente en él, de forma que no tengas que empezar desde 0.
Para usar la aplicación de ejemplo sigue los siguientes pasos:
Este documento es un extracto de la documentación oficial del Framework ZK, traducido y ampliado por Francisco Ferri. Colaborador de Potix (creadores del Framework ZK). Si quieres contactar con él puedes hacerlo en franferri@gmail.com, en twitter @franciscoferri o en LinkedIn