iT邦幫忙

2021 iThome 鐵人賽

DAY 17
1
Modern Web

ZK 30天速成系列 第 17

Shadow Element:建構新增、刪除、排序集合物件的介面與功能

走訪集合物件

<forEach> 跟 Listbox, Grid 同樣支援 model-driven rendering,也就是基於 ListModel 來繪製畫面,你只要變更 ListModel 物件內容,ZK 會自動幫你更新到瀏覽器頁面。例如下面是一個新增、刪除、排序名字列表的應用:

顯示名字列表

https://ithelp.ithome.com.tw/upload/images/20211002/200506216JlBT9Fp2h.jpg

<groupbox width="450px" apply="quickstart.shadow.ForEachComposer" mold="3d">
    <div>
        <forEach id="namesList" var="name">
            <span  sclass="nameTag">
                <label value="${name}"/>
            </span>
        </forEach>
    </div>
</groupbox>
  • 指定 <forEach> id 好讓我可以在控制器中取得參照。var 屬性是把預設的隱含變數名稱 each 改名為 name,這樣在 <forEach> 內部就必須要用 ${name} 來存取集合物件內每個物件,這是一個增加可讀性的功能,不改也不影響功能。
public class ForEachComposer extends SelectorComposer<Component> {
    
    @Wire("::shadow#namesList")
    private ForEach namesList;
    private ListModelList<String> namesModel;

    @Override
    public void doAfterCompose(Component comp) throws Exception {
        super.doAfterCompose(comp);
        namesModel = new ListModelList<String>(new String[] {"Chris", "Elisabeth", "Aaron", "Berta", "Daniel"});
        namesList.setItems(namesModel);
        namesList.recreate();
  • setItems() 把初始化好的資料模型 ListModelList 賦予給 nameList,再呼叫 recreate() 重建 <forEach> 的元件

新增名字到列表中

https://ithelp.ithome.com.tw/upload/images/20211002/20050621LZvgMCB9co.jpg
增加一個 <textbox> 並把事件轉發到根元件上。

<groupbox width="450px" apply="quickstart.shadow.ForEachComposer" mold="3d">
    <div>
        <forEach id="namesList" var="name">
            <span  sclass="nameTag">
                <label value="${name}"/>
            </span>
        </forEach>
    </div>
		<textbox forward="onOK=onAddName" placeholder="New Name + ENTER"/>
</groupbox>
  • onOK 事件發生在使用者在 <textbox> 內按下 Enter 鍵,這樣好處是可以免去點擊「增加」按鈕的操作
  • 轉發事件若不指定目標元件,預設是 ID space owner,但因為畫面上沒有實作 IdSpace的元件,就會轉發到「根元件」,也就是 <groupbox>
@Override
public void doAfterCompose(Component comp) throws Exception {
    super.doAfterCompose(comp);
    ...

    comp.addEventListener("onAddName", (EventListener<ForwardEvent>)this::addName);
}

private void addName(ForwardEvent event) {
    Textbox nameInput = (Textbox) event.getOrigin().getTarget();
    Optional.ofNullable(nameInput.getValue())
            .filter(v -> !namesModel.contains(v)) //ignore duplicates
            .ifPresent(namesModel::add);
    nameInput.setValue("");
}
  • 另一種註冊事件傾聽器的方法 addEventListener()
  • 呼叫 namesModel::add,zk 就會幫你通知 <forEach> 並更新頁面

移除名字

https://ithelp.ithome.com.tw/upload/images/20211002/20050621wnOvonReXv.jpg
在名字後面增加一個 X 圖示來作為「移除」按鈕

<forEach id="namesList" var="name">
    <span sclass="nameTag" >
        <label value="${name}"/>
        <a forward="onClick=onRemoveName(${name})" iconSclass="z-icon-times"/>
    </span>
</forEach>
  • 將「移除」按鈕的 onClick 事件轉發到 <groupbox>,這樣的好處是,我可以統一把傾聽器都註冊在 <groupbox>,比較好維護。如果註冊在內部子元件 <a>上,如果未來要換成別的元件,就要修改程式
  • 轉發的時候可以帶參數 onRemoveName(${name}):這寫法就能把名字當作參數傳進傾聽器中
public void doAfterCompose(Component comp) throws Exception {
    super.doAfterCompose(comp);
    ...
    comp.addEventListener("onRemoveName", event -> namesModel.remove((String) event.getData()));
}
  • event.getData() 取得先前傳入的參數(名字)

排序

https://ithelp.ithome.com.tw/upload/images/20211002/20050621oyyahsXG8Q.jpg
加2個排序按鈕,分別是升序與降序排序:

<button forward="onSortAsc" iconSclass="z-icon-sort-alpha-asc"/>
<button forward="onSortDesc" iconSclass="z-icon-sort-alpha-desc"/>

呼叫 ListModelList.sort() 來排序即可

@Override
    public void doAfterCompose(Component comp) throws Exception {
        super.doAfterCompose(comp);
        ...
        comp.addEventListener("onSortAsc", event -> namesModel.sort(String.CASE_INSENSITIVE_ORDER));
        comp.addEventListener("onSortDesc", event -> namesModel.sort(String.CASE_INSENSITIVE_ORDER.reversed()));
        ...
    }

清除全部

增加一個清除全部按鈕
https://ithelp.ithome.com.tw/upload/images/20211002/20050621lInsy44XOp.jpg

<button forward="onClearAll" iconSclass="z-icon-user-times" tooltiptext="clear all"/>

呼叫 ListModelList.clear()

@Override
public void doAfterCompose(Component comp) throws Exception {
    super.doAfterCompose(comp);
    ...

    comp.addEventListener("onClearAll", event -> namesModel.clear());
    ...
}

透過以上例子應該可以看出,用 <forEach> 再搭配 ListModelList 即可以快速做出新增、刪除等各種操作集合物件的功能。


上一篇
Shadow Element:條件控制元件的創建、消滅
下一篇
如何讓元件自動調整尺寸適應各種裝置螢幕
系列文
ZK 30天速成30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言