天天看點

Tapestry 4 實作自定義元件-CheckboxList

[本文中的程式在JDK 6, Tapestry 4.1中測試通過]

用Tapestry自定義元件和建立一個page一樣簡單,同樣要建立三個檔案,html模闆,配置檔案,java類檔案,隻不過配置檔案字尾不是page了,而是jwc。

定義元件的html模闆

元件html模闆和page的模闆基本差不多,隻不過元件模闆可以是html的片段,也可以是完整的html檔案。我們要實作的CheckboxList隻需要一個html片段作為模闆:

  1. <table border="0" cellpadding="0" cellspacing="0">
  2. <tr jwcid="allItems">
  3. <td>
  4. <input type="checkbox" jwcid="curItem"/>
  5. <span jwcid="curItemLabel">Checkbox 1<!---->span>
  6. <!---->td>
  7. <!---->tr>
  8. <!---->table>

将一個表格作為模闆,每一個checkbox和一個标簽作為一行。

在CheckboxList.java處理類中,添加兩個元件的參數:

  1. @Parameter(name = "allItems", required = true)
  2. public abstract List <basepojo> getAllItems(); </basepojo>
  3. @Parameter(name = "selectedItems", required = false)
  4. public abstract List <basepojo> getSelectedItems(); </basepojo>

這兩個參數接受使用者指定的所有checkbox項的集合群組件顯示的時候選中項的集合,前者是required,後者是可選的(不指定的話就是不選中任何的checkbox)

在CheckList.jwc檔案中,循環指定給元件參數的allItems:

  1. <property name="curItem"/>
  2. <property name="itemIndex"/>
  1. <component id="allItems" type="For">
  2. <binding name="source" value="allItems"/>
  3. <binding name="value" value="curItem"/>
  4. <binding name="index" value="itemIndex"/>
  5. <binding name="element" value="literal:tr"/>
  6. <!---->component>

将curItem和itemIndex輸出給CheckboxList模闆上的Checkbox元件和Insert元件,分别顯示一個Checkbox和一個标簽:

  1. <component id="curItem" type="Checkbox">
  2. <binding name="id" value="ognl:name"/>
  3. <binding name="value" value="mapping[itemIndex]"/>
  4. <!---->component>
  5. <component id="curItemLabel" type="Insert">
  6. <binding name="value" value="curItem"/>
  7. <!---->component>

注意Checkbox中的value="mapping[temIndex]",這個mapping是一個boolean的數組,和allItems中的項一一對應,裡面辨別了所有的checkbox項的選中情況,某項選中則對應的mapping[i]為true,否則為false。這個mapping 需要我們根據元件使用者給定的兩個參數來生成。renderComponent方法是BaseComponent的用于渲染整個元件的方法,我們需要override該方法并在這裡生成或者說初始化mapping:

CheckboxList.java

  1. private boolean[] mapping = null;
  2. @Override
  3. protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle) {
  4. mapping = new boolean[this.getAllItems().size()];
  5. for(int i=0;i<this.getAllItems().size();i++){
  6. if(getSelectedItems()==null)continue;
  7. mapping[i] = getSelectedItems().contains(this.getAllItems().get(i));
  8. }
  9. super.renderComponent(writer, cycle);
  10. }

然後,你就可以在你的頁面中使用CheckboxList元件來顯示内容了。

在你的頁面中使用CheckboxList元件

  1. <component id="userSelectionList" type="CheckboxList">
  2. <binding name="name" value="literal:userSelectionList"/>
  3. <binding name="allItems" value="ognl:allUsers"/>
  4. <binding name="selectedItems" value="ognl:selectdUsers"/>
  5. <!---->component>

至此,我們的CheckboxList元件已經可以頁面上顯示所有的Checkbox項,并正确選中使用者指定的Checkbox項了。

但是還沒有完,在我們修改這些Checkbox的選中狀态後,如何将改動反映給處理類,使之可以将改動儲存到DB中呢?

可以看到,雖然我們将標明項集合從參數selectedItems傳遞到了我們自定義的CheckboxList元件中,但是真正和Checkbox元件綁定的是mapping,是以當你改變某個Checkbox的選中狀态後相應的mapping的值會改變,而不會改變參數selectedItems的内容。是以,我們需要自己編碼來把他實作了。在前面的CheckboxList.java中的renderComponent後面方法中加入以下語句:

java 代碼

  1. if(cycle.isRewinding()){
  2. List <basepojo> reselectedList = new ArrayList <basepojo>(); </basepojo> </basepojo>
  3. for(int i=0;i<this.getAllItems().size();i++){
  4. if(mapping[i] == false)continue;
  5. reselectedList.add(this.getAllItems().get(i));
  6. }
  7. this.setSelectedItems(reselectedList);
  8. }

調用cycle.isRewinding()方法告訴我們是否是使用者送出表單。

完整的renderComponent方法就是:

@Override
protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle) {
    mapping = new boolean[this.getAllItems().size()];
    for(int i=0;i<this.getAllItems().size();i++){
    if(getSelectedItems()==null)continue;
        mapping[i] = getSelectedItems().contains(this.getAllItems().get(i));
    }
    super.renderComponent(writer, cycle);
    if(cycle.isRewinding()){
        List reselectedList = new ArrayList(); 
        for(int i=0;i<this.getAllItems().size();i++){
        if(mapping[i] == false)continue;
            reselectedList.add(this.getAllItems().get(i));
        }
        this.setSelectedItems(reselectedList);
    }
}
           

這樣,我們CheckboxList就可以和使用者指定的標明項的集合完全的綁定起來,就是說既可以取值也可以設值了,一個具有完整功能的自定義元件也就實作啦!