2012-08-01 16 views
5

Tengo un elemento de nivel de bloque, un contenedor, que debe estar oculto cuando sus elementos secundarios de Wicket (botones) están ocultos. En otras palabras, si cualquier botón secundario está visible, el contenedor debería estar visible.Wicket contenedor que está oculto cuando todos sus componentes secundarios están ocultos

Anteriormente, uno de los botones siempre estaba visible si había algún botón, así que usé ese botón para controlar la visibilidad de un <wicket:enclosure>, manejando todo esto puramente en el lado HTML.

Ahora, las especificaciones han cambiado para que los botones se puedan ocultar/visualizar de forma independiente, por lo que un simple armario ya no funcionará (creo).

lo tengo trabajando con algo como esto:

HTML:

<wicket:container wicket:id="downloadButtons"> 
    <wicket:message key="download.foo.bar"/>: 
    <input type="button" wicket:id="excelDownloadButton" wicket:message="value:download.excel"/> 
    <input type="button" wicket:id="textDownloadButton" wicket:message="value:download.text"/> 
    <!-- etc ... --> 
</wicket:container> 

Java:

WebMarkupContainer container = new WebMarkupContainer("downloadButtons"); 

// ... add buttons to container ... 

boolean showContainer = false; 
Iterator<? extends Component> it = container.iterator(); 
while (it.hasNext()) { 
    if (it.next().isVisible()) { 
     showContainer = true; 
     break; 
    } 
} 
addOrReplace(container.setVisible(showContainer)); 

Pero el lado de Java es ahora tipo de verbosa y feo, y yo estaba pensando en , probablemente haya una manera más limpia de hacer lo mismo. ¿Esta ahí? ¿Puede de alguna manera "automáticamente" ocultar un contenedor (con todas sus marcas adicionales) cuando ninguno de sus componentes secundarios está visible?

(Wicket 1.4, si importa.)

Respuesta

10

Si desea que esto sea reutilizable, se se puede definir como un IComponentConfigurationBehavior (por portillo versión> 1.4.16) que se adjunta a cualquier contenedor y luego establecer la visibilidad de contenedores en el método onConfigure() del comportamiento:

class AutoHidingBehavior extends AbstractBehavior { 

    @Override 
    public void bind(Component component) { 
     if (! (component instanceof MarkupContainer)) { 
      throw new IllegalArgumentException("This behavior can only be used with markup containers"); 
     } 
    } 

    @Override 
    public void onConfigure(Component component) { 
     MarkupContainer container = (MarkupContainer) component; 
     boolean hasVisibleChildren = false; 
     for (Iterator<? extends Component> iter = container.iterator(); iter.hasNext();) { 
      if (iter.next().isVisible()) { 
       hasVisibleChildren = true; 
       break; 
      } 
     } 
     container.setVisible(hasVisibleChildren); 
    } 

} 
+0

Agradable; este enfoque era nuevo para mí, y ahora que lo implementé en nuestro código, es bastante elegante también. (La página original está muy simplificada, y esto promueve la reutilización). – Jonik

4

Se podría reemplazar el método del contenedor isVisible a devolver verdadero si cualquiera de los niño es visible (la evaluación de la visibilidad niño como lo hace ahora). Esto no reduciría drásticamente el código, pero sería "más agradable" a mis ojos porque la visibilidad que determina el código sería donde pertenece. Podrías hacer de esto una clase contenedor especial para encapsular aún más el código.

O puede crear la subclase EnclosureContainer y agregar la lógica de visibilidad que necesite.

Nota: Al reemplazar isVisible ...

[...] se advirtió que esto tiene algunas trampas:

  • se llama varias veces a la petición, potencialmente decenas de veces, así que mantenga la implementación computacionalmente ligera

  • este valor debe permanecer estable a través del límite render/responder. Es decir, si isVisible() devuelve verdadero cuando la prestación de un botón, pero cuando el botón se hace clic en los retornos falsos obtendrá un error

de Wicket in Action

+0

Gracias. Acerca de EnclosureContainer: puede usarlo sí, pero, a mi entender, no tendría ningún beneficio sobre, p. WebMarkupContainer aquí. Corrígeme si estoy equivocado. (Quiere que * one * componente hijo controle la visibilidad; si tuviera solo uno sería realmente útil). – Jonik

+0

Estaba buscando principalmente una manera de evitar el código de iteración un tanto feo para determinar la visibilidad del contenedor. Tenía una corazonada Sería de alguna manera. Pero, por supuesto, si ese código es lo más limpio posible, también es una respuesta válida ... – Jonik

+0

+1: Pero probablemente sea mejor subclasificar WebMarkupContainer y agregar allí la verificación de visibilidad. Escribí tal clase la semana pasada por exactamente esta razón. –

0

También puede usar visitante.

En mi caso tengo un contenedor con enlaces en el Panel. Código:

public abstract class MyPanel extends Panel 
{ 
    private final WebMarkupContainer webMarkupContainer; 

    public MyPanel(String id) 
    { 
     super(id); 

     webMarkupContainer = new WebMarkupContainer("customContainer") 
     { 
     @Override 
     protected void onBeforeRender() 
     { 
      super.onBeforeRender(); 
      boolean visible = Boolean.TRUE.equals(checkVisibleLinks()); 
      setVisible(visible); 
     } 
     }; 

     AjaxLink myLink = new AjaxLink("myLink") 
     { 
     @Override 
     public void onClick(AjaxRequestTarget target) 
     { 
      //some action 
     } 

     }; 

     webMarkupContainer.add(myLink); 
    } 

    private Boolean checkVisibleLinks() 
    { 
     return webMarkupContainer.visitChildren(AbstractLink.class, new IVisitor<AbstractLink, Boolean>() 
     { 
     @Override 
     public void component(AbstractLink link, IVisit<Boolean> visit) 
     { 
      if (link.isVisible()) 
      { 
       visit.dontGoDeeper(); 
       visit.stop(true); 
      } 
     } 
     }); 
    } 

} 
Cuestiones relacionadas