2012-08-01 5 views
5

Mam element blokowy, kontener, który powinien być ukryty, gdy jego elementy Wicket (guziki) są ukryte. Innymi słowy, jeśli widoczny jest przycisk podrzędny dla dziecka, pojemnik powinien być widoczny.Kontener wicket, który jest ukryty, gdy wszystkie jego składniki podrzędne są ukryte.

Wcześniej jeden z przycisków był zawsze widoczny, jeśli były jakieś przyciski, więc użyłem tego przycisku do kontrolowania widoczności <wicket:enclosure>, obsługując to wszystko po stronie HTML.

Teraz specyfikacje uległy zmianie, dzięki czemu przyciski mogą być ukryte/widoczne niezależnie, więc prosta obudowa nie będzie działać (myślę).

mam go pracy z czymś takim:

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)); 

Ale strona Java jest teraz trochę rozwlekły i brzydki, a ja myślenie prawdopodobnie jest czystszy sposób, aby zrobić to samo. Jest tu? Czy w jakiś sposób "automatycznie" można ukryć kontener (ze wszystkimi dodatkowymi znacznikami), gdy żaden z jego komponentów podrzędnych nie jest widoczny?

(Furtka 1.4, jeśli ma to znaczenie).

Odpowiedz

10

Jeśli chcesz to być wielokrotnego użytku, ty można określić je jako IComponentConfigurationBehavior (dla wersji furtki> 1.4.16), które można podłączyć do wszystkich pojemników, a następnie ustawić widoczność kontenera w metodzie onConfigure() zachowania:

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

Nice; To podejście było dla mnie nowością, a teraz, gdy zaimplementowałem je w naszym kodzie, jest całkiem eleganckie. (Oryginalna strona jest znacznie uproszczona, a to promuje ponowne użycie). – Jonik

4

Można zastąpić isVisible metodę kontenera, aby powrócić true, jeśli którykolwiek z Childs jest widoczny (oceny widoczności dziecko jak ty teraz). Nie zmniejszyłoby to drastycznie kodu, ale byłoby to "przyjemniejsze" w moich oczach, ponieważ kod określający widoczność byłby tam, gdzie "należy". Można to uczynić wyspecjalizowaną klasą kontenerów, aby jeszcze bardziej zamknąć kod.

Albo możesz podklasę EnclosureContainer i dodać dowolną logikę widoczności, której potrzebujesz.

Uwaga: Kiedy przesłanianie isVisible ...

[...] powinien być ostrzeżony, że ma kilka pułapek:

  • nazywa się to wiele razy na żądanie, potencjalnie dziesiątki razy, więc utrzymuj obliczeniowo niewielką implementację, wartość ta powinna pozostać stabilna na granicy renderowania/odpowiedzi. Czyli jeśli isVisible() zwraca true podczas renderowania przycisk, ale gdy kliknięciu przycisku zwraca false dostaniesz błąd

od Wicket in Action

+0

Dzięki. O EnclosureContainer: możesz go użyć tak, ale według mojego zrozumienia nie przyniosłoby to żadnych korzyści ponad np. WebMarkupContainer tutaj. Popraw mnie, jeśli się mylę. (Chce, aby * jeden * komponent potomny kontrolował widoczność - gdybym miał tylko jeden, byłby naprawdę przydatny). – Jonik

+0

Szukałem głównie sposobu na uniknięcie nieco brzydkiego kodu iteracyjnego w celu określenia widoczności kontenera - miałem przeczucie w jakiś sposób. Ale oczywiście, jeśli ten kod jest tak czysty, jak to tylko możliwe, jest to również ważna odpowiedź ... – Jonik

+0

+1: Ale prawdopodobnie lepiej jest podklasować WebMarkupContainer i dodać tam kontrolę widoczności. Napisałem taką klasę właśnie w zeszłym tygodniu właśnie z tego powodu. –

0

Możesz również użyć gościa.

W moim przypadku mam pojemnik z łączami w Panelu. Kod:

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); 
      } 
     } 
     }); 
    } 

} 
Powiązane problemy