1

I am currently using a dynamic tree in zk. The code is the following :

<tree id="treeview"  multiple="true" width="330px" model="@load(vm.treeModel)"
                          style="border: 1px solid #9D9D9D;"  vflex="1" rows="14" >
                        <treecols sizable="true">
                            <treecol />
                        </treecols>
                        <template name="model">
                            <treeitem>
                                <treerow>
                                    <treecell><checkbox label="@load(each.data.name)" checked="true"/></treecell>
                                </treerow>
                            </treeitem>
                        </template>
                  </tree>

I want that if I uncheck a parent checkbox all the child must be unchecked. And the vice versa should also happen i.e. if I check a parent checkbox,all child must be checked.

Is there any attribute available for tree tag in zk to do this? If not, what are the other ways of doing it?

  • Possible duplicate of [How to make child Tree Items checked/un-checked if parent Tree was made checked/un-checked](http://stackoverflow.com/questions/25197047/how-to-make-child-tree-items-checked-un-checked-if-parent-tree-was-made-checked) – pamps Oct 28 '16 at 18:32

2 Answers2

0

I was facing the same issue and came up with a client side only solution that is fast and accurately throws the proper selection events.

To enable it, in your tree item renderer, add this widget listener:

treeitem.setWidgetListener(Events.ON_CLICK, "selectSubTreesOnItemClick(this, event);");

In your case (template), do it like this:

<tree xmlns:w="client">
  ...
    <treeitem w:onClick="selectSubTreesOnItemClick(this, event)">

Then, import the following js file (in your zul, add <script src="/js/treeselection.js" /> somewhere):

function selectSubTreesOnItemClick(item, event) {
    // if clicked outside of check box, reset selection
    if (!jq(event.target).is('.z-treerow')) {
        item.getTree().clearSelection();

        // re-select clicked node
        item.setSelected(true);
    }

    privateSelectDescendants(item);

    privateSelectParentIfAllDescendantsSelected(item);

    // update selection
    item.getTree().fireOnSelect(item);

    // prevent interference of the tree's default click behavior (like selection of the clicked node ;) ).
    event.stop();
}

/**
 * @param parent if selected, selects all children (and grand-children and so on), otherwise
 *                  removes them from selection.
 */
function privateSelectDescendants(parent) {
    var items = parent.getTree().itemIterator();

    // find all descendants of parent
    while (items.hasNext() && items.next() !== parent) {}
    var stopAt = privateGetFirstNonDescendant(parent);

    // check descendants
    while (items.hasNext()) {
        var descendant = items.next();
        if (descendant === stopAt) {
            break;
        } else {
            descendant.setSelected(parent.isSelected());
        }
    }
}

/**
 * @param item parent will be selected if item and all its siblings are selected, otherwise
 *                 unselected. Repeated for grandparents, great-grandparents, and so on.
 */
function privateSelectParentIfAllDescendantsSelected(item) {
    if (item.getParentItem() != null) {
        var parent = item.getParentItem();

        // find all descendants of parent
        var items = parent.getTree().itemIterator();
        while (items.hasNext()) {
            if (items.next() === parent){
                break;
            }
        }
        var stopAt = privateGetFirstNonDescendant(parent);

        // check descendants
        var allDescendantsSelected = true;
        while (items.hasNext()) {
            var child = items.next();
            if (child === stopAt) {
                break;
            } else if (!child.isSelected()) {
                allDescendantsSelected = false;
                break;
            }
        }
        parent.setSelected(allDescendantsSelected);

        // continue with grandparents
        privateSelectParentIfAllDescendantsSelected(parent);
    }
}

/**
 * @param item
 * @returns the next item that is on the same or a higher level as item. 
 *             Undefined if item is the last node or only followed by children.
 */
function privateGetFirstNonDescendant(item) {
    var result = item.nextSibling;

    while (!result && item.getParentItem() != null) {
        item = item.getParentItem();
        result = item.nextSibling;
    }

    return result;
}

(Un)Selecting a tree node will also (un)select its descendants. Furthermore, if all the node's siblings are selected, the parent node will be selected, otherwise unselected (this goes all the way up to the root node).

Malte Hartwig
  • 4,477
  • 2
  • 14
  • 30
0

You can use Zscript for your purpose, by onclick event you link to a function and pass the Treeitem as a parameter. The function evaluates if it has children, cycles through the children and sets depending on whether the parent is selected. In case there are many nested ones you can use a recursive function.

<zscript><![CDATA[
  public void selectItemsChildren(Treeitem item){
    item.setOpen(true);
    if(!item.isEmpty())
      for(Treeitem p : item.getTreechildren().getItems()){
        p.setSelected(item.isSelected());
      }
    }
  ]]>
</zscript> 
<tree id="treeAccess" width="100%" model="@bind(vm.treeModel)">
  <treecols>
    <treecol hflex="1" label="Description"/>
  </treecols>
  <template name="model">
    <treeitem onClick="selectItemsChildren(self)">
      <treerow>
        <treecell label="@load(each...any)"/>
      </treerow>
    </treeitem>
  </template>
</tree>