Comment on page
ZK
- 使用
<?import wtf.foo>
而不是在<zscript>
中寫import wtf.foo;
。
測試環境:
- Eclipse Luna
- Maven project
用 Server View 指定外部 Tomcat、然後 project 用 Run on Server 的方法。
- 1.開 Preferences
- 2.左邊選擇 General / Content Types
- 1.右邊中間選擇 Text / XML (Illformed)
- 2.新增 *.zul
- 3.左邊選擇 General / File Associations
- 1.新增 *.zul
- 2.下方 Associated editors 選擇 XML Editor 後按下「Default」按鈕
- 用 external editor 修改 ZUL,需要要求 Tomcat 重新 publish 才能讀得到,不然就是 Navigator View 重新 refresh。簡單地說就是 Eclipse 不知道 ZUL 改了,所以不會叫 Tomcat 更新 ZUL。
- 另外要注意 Navigator View 當下必須包含該 ZUL(如果有作 zoom in 就會有這個問題),不然重新 publish 還是一樣讀到舊的...
- 有遇到 publish 也無法更新 ZUL 的狀況,一定要到 Navigator View 作 refresh 才行。沒特殊需求還是乖乖用 Eclipse 內建 XML editor 就算了... [死]
- 修改 MVVM 的 ViewModel,不用想了,一定要重新 restart Tomcat
使用
@Wire
、@WireVariable
必須在 @Init
的 method 以後才會有實際值。注意:
Window
是獨立的 IdSpace,也就是你無法直接 wire Window
裡頭的 component, 而必須從 Window
開始指進去,例如 @Wire("#fooWindow #foo")
透過 MVVM 觸發了一個
@Command
method doFoo()
, 在 doFoo()
中呼叫另一個 @Command
method doWTF()
, 這裡必須注意在 doFoo()
中呼叫 doWTF()
是單純的 Java method call, 跟 MVVM 一點關係也沒有,所以 doWTF()
掛的那堆 @NotifyChange
完全不會被觸發。解決方法是自己發 event 給 MVVM 的機制,例如:
String[] propertyList = {};
for (String property : propertyList) {
BindUtils.postNotifyChange(null, null, this, property);
}
另一種解法是
doFoo()
必須長這樣@Command
public void doFoo(@ContextParam(ContextType.BINDER) final Binder binder) {
//......
//doWTF()
binder.postCommand("doWTF", null);
}
這樣是透過 MVVM 底層機制去觸發
doWTF()
,相關的 @NotifyChange
自然也會觸發了。假設
form
長這樣:form="@id('fx') @load(vm.currentData) @save(vm.currentData, before='save')"
如果有對
currentData
作 notify change,那有 load fx
或是 fxStatus
也會隨之 notify change。假設有一個 field 的 binding 對象是用
ListModelList
,像這樣:在 VM 當中作
fooList.setSelection(Arrays.asList(aFoo))
只會讓畫面顯示正常, 並不會讓 fx.foo
的值變成 aFoo
, 必須自己作 form.setField("foo", aFoo)
。如果 middle object 的 class 會在操作當中改變 (你問為什麼會有這種需求?這是一個很長的故事... [淚目]), 這時會炸出一個 exception,炸點在 ZUL 宣告 form binding 的附近, 內容主要是 property binding 錯誤。 目前找到唯一的解法,就是自己實作一個
MyForm
,內容完全照抄 org.zkoss.bind.impl.FormImpl
,然後加上:public void clear() {
_saveFieldNames.clear();
_loadFieldNames.clear();
_fields.clear();
_initFields.clear();
_dirtyFieldNames.clear();
}
這樣在切換時先呼叫
clear()
再 notify change binding 的 instance, 就不會炸了 \囧/如果 bind
ParentVM
的 component 裡頭有一個 child component 是 bind ChildVM
, 而 ParentVM
跟 ChildVM
都有掛 @Command
的 method 假設叫做 wtf()
。 那麼,在 child component 裡頭的 @command('wtf')
只會觸發 ChildVM.wtf()
,不會連帶觸發 ParentVM.wtf()
@load()
可以用來呼叫 VM 的 method, 例如 @load(vm.foo(each))
就是呼叫 foo()
,然後傳入 each
。這樣子作可以取得發出 event 的 component
@Command
public void wtf(@ContextParam(ContextType.COMPONENT) Component component) { }
這樣子作可以取得發出 event 的 event
@Command
public void wtf(@ContextParam(ContextType.TRIGGER_EVENT) Event event) { }
當然,可以指定 child class、也可以兩個同時一起用。
在
listbox
的 auxhead
中,各個 component 要(視覺上合理地)撐滿, 學理上給 width="100%"
或是 hflex="1"
,當然以 render 速度來說應該設 width 會比較快,不過:- textbox:只能用
hflex="1"
- combobox:都可以
margins 的順序居然是「上、左、右、下」
setCollapsible()
的前提條件是 getTitle
必須有值。- 1.每個 Row 裡頭 component 統一都用 Cell 包起來。
- 2.寫一個 global 的 CSS 對應
- 3.不管什麼 deprecated,繼續用 Row.setSpans()
結果似乎最保險的是最後那個不管 deprecated... 真是幹他媽的好 ZK 阿...
Combobox.setValue()
是對應選到的 Comboitem.getLabel()
, Comboitem
的 value
目前看起來無意義。如果只是要借用 Datebox 顯示、而不讓使用者修改值,那除了
setReadonly(true)
之外還要加上 setButtonVisible(false)
。row
會蓋掉 vflex
的設定。不過如果有觸發 resize,那 vflex
的設定還是會再蓋回來。auxheader
才能作 colspan,listheader
不行; 要出現 auxheader
必須要有 listhead
(空的也無所謂)。 auxheader
設定寬度無效,會依照 listheader
的設定跑。auxhead
如果塞 textbox
之類的元件,建議下 hflex="1"
會比 width="100%"
好看。目前找到畫面載入時預設全選的最簡單方法:
`onAfterRender` 的時候,資料已經 ready 了(先不考慮動態載入資料的問題 Zzzz), 所以 `selectAll()` 可以運作。 在 EE 版,一個有設定 `rod=true` 的 Listbox 是不會出現 select all 的 checkbox。 如果不是在 EE 版,設定 `rod=true`(無論在 zk.xml 還是 ZUL)都會被忽略掉, 所以一定會出現 select all 的 checkbox。 ### nonselectableTags ### Listbox 中的某些 **HTML tag** 的 `onClick` 行為,天生就不會連帶觸發 Listbox 的 `onSelect` 行為, 例如 ``、``、``、``。 然後透過 `nonselectableTags` 這個 attribute,可以重新決定哪些 **HTML tag** 會 / 不會觸發 `onSelect`。 例如希望圖片跟按鈕都不要觸發 `onSelect`,就要這樣寫
nonselectableTags
也可以給 *
,表示不管阿貓阿狗都不會觸發 onSelect
。 然後建議搭配 checkmark="true"
最後,請注意,
nonselectableTags
接受的值是幹他媽的 HTML tag, 不是 ZUL component 名稱,也就是說,你得知道哪些 component 實際上是由什麼 HTML 湊出來的。macro
似乎會預設兩個 style、其中一個是 display:inline-block
。 如果對 macro 作 setVisible(false)
之後再 setVisible(true)
, 這個 macro 的 style 就會被清光光...... WTFZUL 的
onOK
是按下 enter 時候會做的事情。如果設定
rows/cols
,那麼就會無視 width/height/hflex/vflex
的設定, Textbox 的大小會直接以 rows/cols
為準。 所以如果希望 Textbox 是 liquid(大小隨 parent 的大小而變動) 就是設定 multiline="true"
,然後不要給 rows/cols
。Textbox 很容易被 parent 截掉、但是視覺上看不出來(例如在 Grid 當中)。 只能說當 Textbox 是多行狀態(等同於 HTML 的 textarea), 在 Chrome / Firefox 當中,右下角都會出現可以調整大小的 button, 以此作為判斷依據,也可以避免發生「怎麼都沒有 scroll bar」的誤判狀況 Orz。
如果要知道一個 multiple 的 Tree (不是 multiple 的沒有這個問題,用 getSelection() 就好) 剛剛點選 / 取消點選哪個 node, 無法直接從 API 取得,必須要:
- 1.ZUL 的
treeitem
這樣寫 - 2.
tree
的onSelect
在 VM 是:public void treeSelect(@ContextParam(ContextType.TRIGGER_EVENT) SelectEvent<Treeitem, Foo> se) {@SuppressWarnings("unchecked")TreeNode<Foo> node = (TreeNode<Foo>)se.getReference().getValue();}
ZK 7.0 似乎有新增相關的 API:
getPreviousSelectedObject()
,還未測。要有設定
title
的情況下 closable="true"
才會有效果... =="Last modified 3yr ago