Ch08"

From Documentation
 
(One intermediate revision by the same user not shown)
Line 85: Line 85:
 
Split into two <code>Tree</code> components!
 
Split into two <code>Tree</code> components!
  
<pre>&lt;zk xmlns:n=&quot;native&quot;&gt;
+
<source lang="xml">
     &lt;vlayout apply=&quot;org.zkoss.bind.BindComposer&quot; viewModel='@id(&quot;vm&quot;) @init(&quot;org.zkoss.todoZK.viewmodel.SidebarVM&quot;)'  
+
<zk xmlns:n="native">
     onBookmarkChange='@command(&quot;bookmarkChange&quot;, evnt=event)' sclass=&quot;menu&quot;&gt;
+
     <vlayout apply="org.zkoss.bind.BindComposer" viewModel='@id("vm") @init("org.zkoss.todoZK.viewmodel.SidebarVM")'  
         &lt;tree selectedItem=&quot;@bind(vm.docSelectItem)&quot;&gt;
+
     onBookmarkChange='@command("bookmarkChange", evnt=event)' sclass="menu">
             &lt;treechildren&gt;
+
         <tree selectedItem="@bind(vm.docSelectItem)">
                 &lt;treeitem label=&quot;Document&quot; onClick='@command(&quot;showDocument&quot;)'&gt;
+
             <treechildren>
                     &lt;treechildren&gt;
+
                 <treeitem label="Document" onClick='@command("showDocument")'>
                         &lt;treeitem label=&quot;About&quot; onClick='@command(&quot;showAbout&quot;)' /&gt;
+
                     <treechildren>
                         &lt;treeitem label=&quot;Release Log&quot; onClick='@command(&quot;showRelease&quot;)' /&gt;
+
                         <treeitem label="About" onClick='@command("showAbout")' />
                     &lt;/treechildren&gt;
+
                         <treeitem label="Release Log" onClick='@command("showRelease")' />
                 &lt;/treeitem&gt;
+
                     </treechildren>
             &lt;/treechildren&gt;
+
                 </treeitem>
         &lt;/tree&gt;
+
             </treechildren>
 +
         </tree>
  
         &lt;tree model=&quot;@load(vm.boardModel)&quot; selectedItem=&quot;@bind(vm.selectedItem)&quot; hflex=&quot;1&quot;&gt;
+
         <tree model="@load(vm.boardModel)" selectedItem="@bind(vm.selectedItem)" hflex="1">
             &lt;template name=&quot;model&quot; var=&quot;board&quot;&gt;
+
             <template name="model" var="board">
                 &lt;treeitem label=&quot;@load(board.data.title)&quot; /&gt;
+
                 <treeitem label="@load(board.data.title)" />
             &lt;/template&gt;
+
             </template>
         &lt;/tree&gt;
+
         </tree>
     &lt;/vlayout&gt;
+
     </vlayout>
&lt;/zk&gt;</pre>
+
</zk>
 +
</source>
 
(You can't merge two <code>Tree</code> into one, because the component with <code>&lt;template&gt;</code> will ignore all other child component.)
 
(You can't merge two <code>Tree</code> into one, because the component with <code>&lt;template&gt;</code> will ignore all other child component.)
  
 
Write them directly in ZUL, thus the operation of selected item is clear. If system need to add, delete or modify static page item, the routine is easier too. But we must do one more thing to remove <code>selectedItem</code> of one <code>Tree</code> if the other <code>Tree</code> is selected. Without this fix, it could be two selectedItem on the screen. The solution is easy:
 
Write them directly in ZUL, thus the operation of selected item is clear. If system need to add, delete or modify static page item, the routine is easier too. But we must do one more thing to remove <code>selectedItem</code> of one <code>Tree</code> if the other <code>Tree</code> is selected. Without this fix, it could be two selectedItem on the screen. The solution is easy:
  
<pre>/**
+
<source lang="java">
 +
/**
 
  * Do nothing, just trigger NotifyChange to clear other tree's selectedItem.
 
  * Do nothing, just trigger NotifyChange to clear other tree's selectedItem.
 
  */
 
  */
@NotifyChange(&quot;selectedItem&quot;)
+
@NotifyChange("selectedItem")
 
public void setDocSelectItem(TreeNode selectedItem) {}
 
public void setDocSelectItem(TreeNode selectedItem) {}
  
Line 128: Line 131:
 
public TreeNode getSelectedItem() {
 
public TreeNode getSelectedItem() {
 
     return null;
 
     return null;
}</pre>
+
}
 +
</source>
 +
 
 
== Alternatives of <code>Tree</code> ==
 
== Alternatives of <code>Tree</code> ==
  
 
As we talk before, you can implement [http://todo-zk.appspot.com ToDoZK] requirement with other component. In <code>sidebar.zul</code>, we can also use <code>Tabpanel</code> (with accordion mold), <code>Grid</code> (with <code>Group</code> component)... etc. There is an example we use <code>Groupbox</code> and <code>Listbox</code>:
 
As we talk before, you can implement [http://todo-zk.appspot.com ToDoZK] requirement with other component. In <code>sidebar.zul</code>, we can also use <code>Tabpanel</code> (with accordion mold), <code>Grid</code> (with <code>Group</code> component)... etc. There is an example we use <code>Groupbox</code> and <code>Listbox</code>:
  
<pre>&lt;div children=&quot;@load(vm.workspaces)&quot;&gt;
+
<source lang="xml">
     &lt;template name=&quot;children&quot; var=&quot;ws&quot;&gt;
+
<div children="@load(vm.workspaces)">
         &lt;groupbox mold=&quot;3d&quot;&gt;
+
     <template name="children" var="ws">
             &lt;caption label=&quot;@load(ws.title)&quot; /&gt;
+
         <groupbox mold="3d">
             &lt;listbox model=&quot;@load(ws.milestones)&quot;&gt;
+
             <caption label="@load(ws.title)" />
                 &lt;template name=&quot;model&quot; var=&quot;ms&quot;&gt;
+
             <listbox model="@load(ws.milestones)">
                     &lt;listitem label=&quot;@load(ms.title)&quot; /&gt;
+
                 <template name="model" var="ms">
                 &lt;/template&gt;
+
                     <listitem label="@load(ms.title)" />
             &lt;/listbox&gt;
+
                 </template>
         &lt;/groupbox&gt;
+
             </listbox>
     &lt;/template&gt;
+
         </groupbox>
&lt;/div&gt;</pre>
+
     </template>
<blockquote>==== To System Architecture ====
+
</div>
 +
</source>
 +
 
 +
<blockquote>
 +
==== To System Architecture ====
  
 
There is no standard answer of the question: &quot;Which component is fittest for my requirement&quot;. Realize all the ZK components and think more. (Or pay to ZK for custom component!)
 
There is no standard answer of the question: &quot;Which component is fittest for my requirement&quot;. Realize all the ZK components and think more. (Or pay to ZK for custom component!)
 
</blockquote>
 
</blockquote>

Latest revision as of 07:30, 11 March 2013

Component Choice

No, you've already made the choice. Now you have to understand it. -- Oracle from "The Matrix Reloaded"

Component Choice Guide

ZK provide too much component, sometime we lost in them... But we still can find some thread of thought, follow these threads we can find the needed component in a short time.

If you need arrange a set components in specify way, we recommend you search in layout category first and don't forget Grid component that is not in layout category. On the other hand, if you don't need arrange them, you can search in container category. The components in container category usually can set title attribute and has Caption component.

If you want to show a set of tuple data, please check Grid, Listbox, Tree suit your requirement or not. Grid is powerful, can provide more free format. Listbox has selectedItem attribute can get the end user selected data more easier. You can treat Tree as an advance Listbox, because it like Listbox but can handle hierarchy data. Of course, you can combine Vlayout and other component to produce handmade layout if the present data is less and simple.

Please don't forget Popup, if you need tooltip, context menu, popup. For more information please refer to ZK codument.

Thinking in component

Choose correct component is important, but use them correctly is important too. We use sidebar.zul in ToDoZK for example to think about this issue.

First idea

Use Tree to build Sidebar is intuition and reasonable. No matter the relation of workspace/milestone or Document Page/Release Log is heirarchy. We hope solve all things with a Tree is natural:

<zk xmlns:n="native">
    <div apply="org.zkoss.bind.BindComposer" viewModel='@id("vm") @init("org.zkoss.todoZK.viewmodel.SidebarVM")' 
     onBookmarkChange='@command("bookmarkChange", evnt=event)' sclass="menu">
        <tree model="@load(vm.boardModel)" selectedItem="@save(vm.selectedItem)" hflex="1">
            <template name="model" var="board">
                <treeitem label="@load(board.data.title)" />
            </template>
        </tree>
    </div>
</zk>

Look at this beautiful ZUL, very pleasant. But when we build the model of Tree, that will be a nightmare. First you must create BoardItem class, because all object in tree model must be the same class:

public class BoardItem {
    public static final int WORKSPACE_TYPE = -1;
    public static final int MILESTONE_TYPE = -2;
    public static final int ROOT_PAGE_TYPE = 1;
    public static final int ABOUT_PAGE_TYPE = 2;
    public static final int LOG_PAGE_TYPE = 3;
    private String title;
    private Long id;
    private int type;
    //skip getter and setter
}

We can't evade the routine of transform workspace/milestone data to BoardItem. But the code of build "Document Page", "Release Log" BoardItem is ugly:

    //in view model's init()
    DefaultTreeNode<BoardItem> root = new DefaultTreeNode<BoardItem>(null, new ArrayList<DefaultTreeNode<BoardItem>>());
    boardModel = new DefaultTreeModel<BoardItem>(root);

    //static page
    DefaultTreeNode<BoardItem> pageRoot = new DefaultTreeNode<BoardItem>(
        new BoardItem(Long.MIN_VALUE, "Document", BoardItem.ROOT_PAGE_TYPE),
        new ArrayList<DefaultTreeNode<BoardItem>>()
    );
    pageRoot.add(
        new DefaultTreeNode<BoardItem>(
            new BoardItem(Long.MIN_VALUE, "About", BoardItem.ABOUT_PAGE_TYPE)
        )
    );
    pageRoot.add(
        new DefaultTreeNode<BoardItem>(
            new BoardItem(Long.MIN_VALUE, "Release Log", BoardItem.LOG_PAGE_TYPE)
        )
    );        
    root.add(pageRoot);
    boardModel.addOpenObject(pageRoot);

    //convert workspace and milestone......

We must give the meaningless id value, must maintain type value is unique, the setSelectedItem() of view model must process these special instance...... The result is dirty code hard to maintain.

Refactoring

Split into two Tree components!

<zk xmlns:n="native">
    <vlayout apply="org.zkoss.bind.BindComposer" viewModel='@id("vm") @init("org.zkoss.todoZK.viewmodel.SidebarVM")' 
    onBookmarkChange='@command("bookmarkChange", evnt=event)' sclass="menu">
        <tree selectedItem="@bind(vm.docSelectItem)">
            <treechildren>
                <treeitem label="Document" onClick='@command("showDocument")'>
                    <treechildren>
                        <treeitem label="About" onClick='@command("showAbout")' />
                        <treeitem label="Release Log" onClick='@command("showRelease")' />
                    </treechildren>
                </treeitem>
            </treechildren>
        </tree>

        <tree model="@load(vm.boardModel)" selectedItem="@bind(vm.selectedItem)" hflex="1">
            <template name="model" var="board">
                <treeitem label="@load(board.data.title)" />
            </template>
        </tree>
    </vlayout>
</zk>

(You can't merge two Tree into one, because the component with <template> will ignore all other child component.)

Write them directly in ZUL, thus the operation of selected item is clear. If system need to add, delete or modify static page item, the routine is easier too. But we must do one more thing to remove selectedItem of one Tree if the other Tree is selected. Without this fix, it could be two selectedItem on the screen. The solution is easy:

/**
 * Do nothing, just trigger NotifyChange to clear other tree's selectedItem.
 */
@NotifyChange("selectedItem")
public void setDocSelectItem(TreeNode selectedItem) {}

/**
 * @return Always null for reset selectedItem.
 */
public TreeNode getDocSelectItem() {
    return null;
}

/**
 * @return Always null for reset selectedItem.
 */
public TreeNode getSelectedItem() {
    return null;
}

Alternatives of Tree

As we talk before, you can implement ToDoZK requirement with other component. In sidebar.zul, we can also use Tabpanel (with accordion mold), Grid (with Group component)... etc. There is an example we use Groupbox and Listbox:

<div children="@load(vm.workspaces)">
    <template name="children" var="ws">
        <groupbox mold="3d">
            <caption label="@load(ws.title)" />
            <listbox model="@load(ws.milestones)">
                <template name="model" var="ms">
                    <listitem label="@load(ms.title)" />
                </template>
            </listbox>
        </groupbox>
    </template>
</div>

To System Architecture

There is no standard answer of the question: "Which component is fittest for my requirement". Realize all the ZK components and think more. (Or pay to ZK for custom component!)