2012-08-01 103 views
5

我有一個塊級元素,一個容器,當隱藏它的子Wicket元素(按鈕)時,應該隱藏它的所有全部。換句話說,如果任何子按鈕是可見的,容器應該是可見的。在隱藏其所有子組件時隱藏的Wicket容器

如果有按鈕的話,前面的按鈕總是可見的,所以我使用該按鈕來控制<wicket:enclosure>的可見性,純粹在HTML端處理所有這些。

現在,規格已經改變,因此按鈕可以獨立隱藏/可見,所以簡單的外殼將不再工作(我認爲)。

我得到了它這樣的工作:

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

但Java端現在是那種冗長和醜陋,我是思考有可能是一個更乾淨的方式來做同樣的事情。在那兒?你可以以某種方式「自動」隱藏一個容器(及其所有額外的標記),當它的子組件都不可見時?

(檢票1.4,如果它很重要。)

回答

10

時,如果你想這是可重複使用的,如果ISVISIBLE()返回true,則可以將其定義爲對連接至任何容器一個IComponentConfigurationBehavior(對於檢票版本> 1.4.16),然後設置在onConfigure()方法行爲的容器的可見性:

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

不錯;這種方法對我來說是新的,現在我已經在我們的代碼中實現了它,它也非常優雅。 (原始頁面大大簡化,這可以促進重用。) – Jonik 2012-08-01 11:02:45

4

您可以覆蓋容器的isVisible方法返回true,如果任何一個孩子的是可見的(評估孩子的知名度就像你現在做的)。這不會大幅減少代碼,但在我眼中它會更好,因爲確定可見性的代碼就是它所屬的「代碼」。你可以使這個專門的容器類來進一步封裝代碼。

或者您可以子類EnclosureContainer並添加您需要的任何可見性邏輯。

注:當重寫ISVISIBLE ...

[...]警告說,這有幾個缺陷:

  • 它被稱爲每個請求多次,可能幾十次,所以保持實現計算光

  • 這個值應該保持整個渲染/響應邊界的穩定。這意味着渲染一個按鈕, 但按鈕被點擊返回false時,你會得到一個錯誤

Wicket in Action

+0

謝謝。關於EnclosureContainer:你可以使用它,但是據我的理解,它沒有任何好處。 WebMarkupContainer在這裏。如我錯了請糾正我。 (它希望*一個*子組件來控制可見性 - 如果我只有一個,它確實會有用。) – Jonik 2012-08-01 09:02:59

+0

我主要在尋找一種避免有點醜陋的迭代代碼來確定容器可見性的方法 - 我在那裏有一個預感會有某種方式。但是,當然,如果代碼儘可能乾淨,那也是一個有效的答案... – Jonik 2012-08-01 09:05:31

+0

+1:但是最好將WebMarkupContainer子類化並在其中添加可見性檢查。正是因爲這個原因,我上週才寫了這樣的一堂課。 – 2012-08-01 09:54:10

0

您也可以使用訪問者。

在我的情況下,我有容器與面板中的鏈接。代碼:

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

}