為了讓使用者更直覺的修改,我希望能直接點英雄的名字就切換成可修改的輸入元件,修改完後就直接存回後端。
修改英雄,首先要先調整頁面元件,將原本的 <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);
}
#heroBox
上的 onChange
事件ForwardEvent
,如果不是轉發事件,就要根據不同的事件宣告不同的事件參數型態event.getOrigin()
: 從 ForwardEvent
上取得來源事件(就是轉發前的 onChange
)getTarget()
: 回傳事件發生的目標元件,本例來說是 <textbox>
,因為原本是使用者修改 <textbox>
的值才觸發的事件nonselectableTags
,所以當使用者點英雄名字時,也會造成選擇了該項目,我就可以透過 heroList
取得正被選擇的項目,並取得對應的、被修改的 Hero
物件<textbox>
中儲存的新名字設到 Hero
物件中,完成更新透過運用元件的特性,就可以立刻做出"文字—輸入"原地置換的效果,而你只要處理伺服器的實作就好。