Ch08"

From Documentation
(Created page with "= Component Choice = <blockquote>No, you've already made the choice. Now you have to understand it. -- Oracle from "The Matrix Reloaded" </blockquote> = Component Cho...")
 
Line 22: Line 22:
 
Use <code>Tree</code> to build <code>Sidebar</code> 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 <code>Tree</code> is natural:
 
Use <code>Tree</code> to build <code>Sidebar</code> 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 <code>Tree</code> is natural:
  
<pre>&lt;zk xmlns:n=&quot;native&quot;&gt;
+
<source lang="xml">
     &lt;div 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;
+
     <div apply="org.zkoss.bind.BindComposer" viewModel='@id("vm") @init("org.zkoss.todoZK.viewmodel.SidebarVM")'  
         &lt;tree model=&quot;@load(vm.boardModel)&quot; selectedItem=&quot;@save(vm.selectedItem)&quot; hflex=&quot;1&quot;&gt;
+
     onBookmarkChange='@command("bookmarkChange", evnt=event)' sclass="menu">
             &lt;template name=&quot;model&quot; var=&quot;board&quot;&gt;
+
         <tree model="@load(vm.boardModel)" selectedItem="@save(vm.selectedItem)" hflex="1">
                 &lt;treeitem label=&quot;@load(board.data.title)&quot; /&gt;
+
             <template name="model" var="board">
             &lt;/template&gt;
+
                 <treeitem label="@load(board.data.title)" />
         &lt;/tree&gt;
+
             </template>
     &lt;/div&gt;
+
         </tree>
&lt;/zk&gt;</pre>
+
     </div>
 +
</zk>
 +
</source>
 +
 
 
Look at this beautiful ZUL, very pleasant. But when we build the model of <code>Tree</code>, that will be a nightmare. First you must create <code>BoardItem</code> class, because all object in tree model must be the same class:
 
Look at this beautiful ZUL, very pleasant. But when we build the model of <code>Tree</code>, that will be a nightmare. First you must create <code>BoardItem</code> class, because all object in tree model must be the same class:
  
<pre>public class BoardItem {
+
<source lang="java">
 +
public class BoardItem {
 
     public static final int WORKSPACE_TYPE = -1;
 
     public static final int WORKSPACE_TYPE = -1;
 
     public static final int MILESTONE_TYPE = -2;
 
     public static final int MILESTONE_TYPE = -2;
Line 44: Line 48:
 
     private int type;
 
     private int type;
 
     //skip getter and setter
 
     //skip getter and setter
}</pre>
+
}
 +
</source>
 +
 
 
We can't evade the routine of transform workspace/milestone data to <code>BoardItem</code>. But the code of build &quot;Document Page&quot;, &quot;Release Log&quot; <code>BoardItem</code> is ugly:
 
We can't evade the routine of transform workspace/milestone data to <code>BoardItem</code>. But the code of build &quot;Document Page&quot;, &quot;Release Log&quot; <code>BoardItem</code> is ugly:
  
<pre>   //in view model's init()
+
<source lang="java">
     DefaultTreeNode&lt;BoardItem&gt; root = new DefaultTreeNode&lt;BoardItem&gt;(null, new ArrayList&lt;DefaultTreeNode&lt;BoardItem&gt;&gt;());
+
    //in view model's init()
     boardModel = new DefaultTreeModel&lt;BoardItem&gt;(root);
+
     DefaultTreeNode<BoardItem> root = new DefaultTreeNode<BoardItem>(null, new ArrayList<DefaultTreeNode<BoardItem>>());
 +
     boardModel = new DefaultTreeModel<BoardItem>(root);
  
 
     //static page
 
     //static page
     DefaultTreeNode&lt;BoardItem&gt; pageRoot = new DefaultTreeNode&lt;BoardItem&gt;(
+
     DefaultTreeNode<BoardItem> pageRoot = new DefaultTreeNode<BoardItem>(
         new BoardItem(Long.MIN_VALUE, &quot;Document&quot;, BoardItem.ROOT_PAGE_TYPE),
+
         new BoardItem(Long.MIN_VALUE, "Document", BoardItem.ROOT_PAGE_TYPE),
         new ArrayList&lt;DefaultTreeNode&lt;BoardItem&gt;&gt;()
+
         new ArrayList<DefaultTreeNode<BoardItem>>()
 
     );
 
     );
 
     pageRoot.add(
 
     pageRoot.add(
         new DefaultTreeNode&lt;BoardItem&gt;(
+
         new DefaultTreeNode<BoardItem>(
             new BoardItem(Long.MIN_VALUE, &quot;About&quot;, BoardItem.ABOUT_PAGE_TYPE)
+
             new BoardItem(Long.MIN_VALUE, "About", BoardItem.ABOUT_PAGE_TYPE)
 
         )
 
         )
 
     );
 
     );
 
     pageRoot.add(
 
     pageRoot.add(
         new DefaultTreeNode&lt;BoardItem&gt;(
+
         new DefaultTreeNode<BoardItem>(
             new BoardItem(Long.MIN_VALUE, &quot;Release Log&quot;, BoardItem.LOG_PAGE_TYPE)
+
             new BoardItem(Long.MIN_VALUE, "Release Log", BoardItem.LOG_PAGE_TYPE)
 
         )
 
         )
 
     );         
 
     );         
Line 69: Line 76:
 
     boardModel.addOpenObject(pageRoot);
 
     boardModel.addOpenObject(pageRoot);
  
     //convert workspace and milestone......</pre>
+
     //convert workspace and milestone......
 +
</source>
 +
 
 
We must give the meaningless <code>id</code> value, must maintain <code>type</code> value is unique, the <code>setSelectedItem()</code> of view model must process these special instance...... The result is dirty code hard to maintain.
 
We must give the meaningless <code>id</code> value, must maintain <code>type</code> value is unique, the <code>setSelectedItem()</code> of view model must process these special instance...... The result is dirty code hard to maintain.
  

Revision as of 07:27, 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!)