Group open not working for custom group model

asked 2020-02-12 01:53:22 +0800

vsriram92 gravatar image vsriram92
33 3

updated 2020-02-13 15:01:25 +0800

I have a custom group model created for my project.

Issue : Group open not working if using BindUtils.postnotifychange();


  1. Close the group1
  2. Click on any item in group2
  3. Try to open group1

Expected result - Group 1 should open Actual result - Group 1 is not opening i.e items are not getting populated.

I'm not sure whether it is a bug or I'm missing something?

Note: BindUtils.postNotifyChange(null, null, SriListViewModel.this, "*"); is very much needed as i'm updating all components in my desktop after a custom javascript change. Any other workaround is much appreciated.

Sample fiddle: https://zkfiddle.org/sample/dnsjiq/15-CustomGroupsModel-dynamic-add-data

Update: invoked postnotifychange for the listmodel again with onOpen event, that fixed the previously mentioned issue.

But Group Open and close while clicking on groupname doesnt work properly. Steps to reproduce:

  1. Close the group1 by clicking on groupname
  2. Click on any item in group2

Expected result - Group 1 should be in closed state Actual result - Group 1 is opened now.

Sample fiddle: https://zkfiddle.org/sample/dnsjiq/21-CustomGroupsModel-dynamic-add-data#source-2

delete flag offensive retag edit


Using 7.0.8 currently. But in fiddle I can see that this persists for ZK 9 too.

vsriram92 ( 2020-02-12 02:05:13 +0800 )edit

Fixed this issue. Fixed fiddle available at https://zkfiddle.org/sample/nb4hk2/1-CustomGroupsModel-expand-collapse-all.

vsriram92 ( 2020-02-18 14:51:06 +0800 )edit

2 Answers

Sort by ยป oldest newest most voted

answered 2020-02-12 15:52:49 +0800

MDuchemin gravatar image MDuchemin
2505 1 6
ZK Team

Hi vsriram92,

The order of operations here is: - Trigger notifyChange on groupModel causes the listbox to invalidate (redraw from scratch). - When first drawing (or invalidating), the listbox will only load open groups children in client memory. - Clicking on a line in group2 causes the listbox to invalidate while group1 is closed, therefore, children of group1 are no longer drawn at client-side.

The normal option would be to use a model listener to update the model based on model events. This is what the default GroupsModel implementation does. (see org.zkoss.zul.impl.GroupsListModel<d, g,="" f=""> )

init is called in the constructor (and a few other places to support serialization, redrawing, etc.) and initialize the listeners on the model:


When the listgroup opens or closes, the component notifies the inner model, Which in turn fires a interval added / interval removed change, causing the listbox to add / remove the relevant listitems. See here

In general, it's a good idea to refer to the default implementation (in this case GroupsListModel) when implementing. Can also be worth just extending ListGroupsModel instead of reimplementing from scratch, unless you need to do something very specific with the group handling.

The easy but hacky workaround would be to also fire the update event when opening the listgroup with a command. Note: THIS IS BAD, Try not doing it :D because you would need to manually re declare everything for every instance.

<template name="model:group" var="groupNameList">
<listgroup label="@load(groupNameList)" onOpen="@command('showAttemptResult',listbox=self.listbox)"  open="false">

PS: karma bump up for links

link publish delete flag offensive edit


I'm unable to fire the ListDataEvent from my view model command. Any other methods to trigger the update event?

vsriram92 ( 2020-02-12 20:41:44 +0800 )edit

Instead of making this post clumsy, I have posted the followup issue at https://forum.zkoss.org/question/112097/expand-all-collapse-all-causing-concurrentmodificationexception/.

vsriram92 ( 2020-02-18 01:44:50 +0800 )edit

answered 2020-02-13 18:27:58 +0800

MDuchemin gravatar image MDuchemin
2505 1 6
ZK Team

The ListDataEvent is not fired from viewModel. The listbox component triggers it directly to the GroupsModel.

You can initialize it like this (based on your sample code):

public SGroupModel() {
    this.multiValueMap = new HashMap<String, List<T>>();
    this.groups = new ArrayList<>();
    this.openStatus = new HashMap<>();
    groupsDataListener = new GroupsDataListener() {
        public void onChange(GroupsDataEvent event) {
            int type = event.getType(), j0 = event.getIndex0(), j1 = event.getIndex1();

            if(type == GroupsDataEvent.GROUPS_OPENED)
                //handle group open / close here
                System.out.println("group open");

From there, you can fire an interval event, trigger init, load from databased, etc. whatever makes sense for your application.

link publish delete flag offensive edit


Btw, you need to remove your addGroupsDataListener override, cause at the moment it does nothing.

MDuchemin ( 2020-02-13 18:28:31 +0800 )edit

You would need to use the default implementation, call super in your custom, or re implement from scratch

MDuchemin ( 2020-02-13 18:29:08 +0800 )edit
Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!

[hide preview]

Question tools

1 follower



Asked: 2020-02-12 01:53:22 +0800

Seen: 10 times

Last updated: Feb 13 '20

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More