iT邦幫忙

2021 iThome 鐵人賽

DAY 11
0
Modern Web

ZK 30天速成系列 第 11

英雄列表範例:修改英雄

為了讓使用者更直覺的修改,我希望能直接點英雄的名字就切換成可修改的輸入元件,修改完後就直接存回後端。

https://ithelp.ithome.com.tw/upload/images/20210926/20050621SeqXzEc2HZ.jpg

頁面設計

修改英雄,首先要先調整頁面元件,將原本的 <label> 換成 <textbox>

<listbox id="heroBox" ...>
    <listhead>
        ...
    </listhead>
    <template name="model">
        <listitem>
            ...
            <listcell>
                <textbox inplace="true" value="${each.name}" width="100%" 
                forward="onChange=heroBox.onChange"/>
            </listcell>
            ...
        </listitem>
    </template>
</listbox>
  • inplace="true" 可以讓 textbox 在沒有 focus 時顯示成 <label> 的外觀,一但使用者點擊該文字,就會立刻轉變成輸入元件 <textbox>
  • 這裡使用 forward 的原因跟前一篇相同,都是因為無法用 @Listen註冊傾聽器在動態產生的元件上
  • onChange 事件發出的時機點是,當使用者輸入後,將焦點(focus) 移出至textbox 外時,該元件就會發出 onChange 事件。我可以註冊對應的傾聽器在伺服器端實作對應的應用程式邏輯來處理名稱修改的情況。如果使用者只是點擊了名字,並沒有修改名字,或是修改之後的名字跟原本相同,元件都不會發出 onChange 事件。

傾聽器實作

當使用者修改名稱之後,雖然可在瀏覽器中看見文字內容變了,但是後端 Hero 物件並沒有改變,這只是使用者瀏覽器上的文字變了,我必須要在傾聽器中把 <textbox> 儲存的值,設到 Hero 物件上去才行。如果你有資料庫,還必須自行呼叫 method 把資料存到資料庫,才是真的更新完成。

@Listen("onChange= #heroBox")
public void change(ForwardEvent event){
    String newName = ((Textbox) event.getOrigin().getTarget()).getValue();
    Hero selectedHero = heroList.getSelection().iterator().next();
    selectedHero.setName(newName);
}
  • 因為 zul 上已經轉發事件,所以我聽得是 #heroBox上的 onChange 事件
  • 這個方法上我宣告了一個參數,如果是轉發事件呼叫的 method,一律都是傳入 ForwardEvent,如果不是轉發事件,就要根據不同的事件宣告不同的事件參數型態
  • event.getOrigin(): 從 ForwardEvent 上取得來源事件(就是轉發前的 onChange
  • getTarget(): 回傳事件發生的目標元件,本例來說是 <textbox>,因為原本是使用者修改 <textbox> 的值才觸發的事件
  • 因為先前設定 nonselectableTags,所以當使用者點英雄名字時,也會造成選擇了該項目,我就可以透過 heroList 取得正被選擇的項目,並取得對應的、被修改的 Hero 物件
  • 最後透過 setter 把 <textbox> 中儲存的新名字設到 Hero 物件中,完成更新

透過運用元件的特性,就可以立刻做出"文字—輸入"原地置換的效果,而你只要處理伺服器的實作就好。


上一篇
英雄列表範例:刪除英雄
下一篇
使用者輸入驗證
系列文
ZK 30天速成30

尚未有邦友留言

立即登入留言