Tenemos
PadrePage.html
<html> <head></head> <body> <wicket:child>Aca va el contenido de la subclase</wicket:child> </body>
class PadrePage extends WebPage new() { this.add(new Label("titulo", "Bienvenido desde la superclase")) }
e HijoMenorPage que hereda de PadrePage
class HijoMenor extends PadrePage y new() { this.add(new Label("saludo", "Hola mundo!")) }
En el html del HijoMenor escribimos
<html> <head></head> <body> --- Todo lo anterior se ignora, es sólo para el diseñador <wicket:extend> <div style="...."> <span wicket:id="saludo">Un saludo</span> </div> </wicket:extend> </body>
¿Qué aprendemos aquí? Que Wicket permite diseñar un template method de pantallas y reutilizar el html fácilmente.
¿Qué hago si necesito tener un componente que quiero mostrar n veces?
Una película, un zombie, un jugador, etc. Lo trabajo mediante composición, a partir de Paneles.
Ejemplo: tenemos un Usuario con nombre (String), dni (String) y cuenta (un Enum). Tenemos una pantalla que muestra los datos del usuario: nombre y DNI. Además tenemos que seleccionar:
La vista es un UsuarioPage (extends WebPage), que tiene como modelo un usuario envuelto en un CompoundPropertyModel. Para mostrar los datos de la cuenta creamos un
val panelCuenta = new CuentaPanel("cuenta", usuario.cuenta)
En el html tenemos
<div wicket:id="cuenta"> DETALLE DE CUENTA </div>
CuentaPanel extiende de Panel y es muy similar a una Page (el único detalle lo veremos después que es un XAttributeModifier).
Puedo referenciar a la página haciendo this.page...
Incluso podríamos definir que sólo se use ese componente en ciertas ventanas a las que yo después le envíe determinados mensajes.
El html del Panel sólo necesita comenzar con:
<wicket:panel> (todo lo anterior no tiene sentido para Wicket, sí para un diseñador con Dreamweaver) <dl> <dt>Tipo:</dt> <dd><span wicket:id="...">Caja de ahorro</span></dd> </dl> </wicket:panel>
Disgresión: se puede configurar en modo Producción para que se eliminen los wicket:id, wicket:panel, wicket:extend, etcétera.
Atravesando límites
Podemos acceder a controles que están dentro de un componente hijo: this.get("cuenta/numero") me permite acceder al componente desde el padre. Esto es desaconsejable porque si no empiezan a proliferar referencias entre padres e hijos. Casos donde puede ser útil:
También podríamos armar un componente genérico que escuche los componentes que necesito refrescar porque cambiaron.
Otra cosa que podemos hacer es
this.get("cuenta").replaceWith(new CuentaPanel("cuenta", usuario.cuenta))
que permite cambiar dinámicamente un componente por otro.
Algunos ejemplos:
Vemos la pantalla
Tipo:
Combo que muestra
Cuenta destino:
El combo de destino va a variar en base a lo que seleccioné en el combo (combos anidados)
Lo que no podemos hacer en el replaceWith es
Sí sirve para mostrar dinámicamente dos paneles
TODO: Implementar un ejemplo copado.
Volvemos al ejemplo de las cuentas bancarias. Recordamos las URL de Grails vs. las de Wicket, que tienen números raros:
http://localhost:8080/misc-avanzados-ui-wicket-xtend/wicket/page?3&sessionId=38423462374a82342384
Ese link no se puede compartir fácilmente, mientras que en Grails era fácil identificar la acción de modificar el libro "Rayuela":
http://localhost:8080/libro-ui-grails/editarLibro/8
(se puede compartir el link a otro usuario).
En Wicket yo se qué botón de qué página apretaron porque tengo estado. No obstante puedo generar "bookmarkable links", o sea links que puedo anotarme como favorito:
http://localhost:8080/misc-avanzados-ui-wicket-xtend/wicket/bookmarkable/org.uqbar.ui.wicket.misc.paneles.UsuarioPage?dni=7.147.129
Para eso construimos un constructor específico:
new(PageParameters parameters) { this(RepositorioUsuario.instance.buscarPorDni(parameter.get("dni").toString)) }
1) El constructor vacío permite que lo usemos desde una página de wicket.
2) El constructor con parámetros permite que le pasemos el dni específico para buscar un modelo en base a ese DNI.
En el ejemplo vemos cómo se genera un a href que vaya a esa página:
... val params = new PageParameters params.add("dni", "7.147.129") this.addChild(new BookmarkablePageLink("usuario13" , UsuarioPage, params)) ...
Y eso permite que nosotros veamos los links y guardarlos en los favoritos del browser.
En CuentaPanel hay un
saldoLabel.addBehavior(new XAttributeModifier("class", [Float saldo | if (saldo < 0) "saldoNegativo" else "" ]))
¿Qué hace? Tarea para el lector: cambia en html el componente dinámicamente. Le agrega al dd un class="saldoNegativo".