Uploaded image for project: 'ZK'
  1. ZK
  2. ZK-3932

zul.sel.Listbox.setSelInView() tries to access non-existing DOM element

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Normal
    • Resolution: Fixed
    • Affects Version/s: 8.5.1.2
    • Fix Version/s: 8.5.2
    • Component/s: ZK Client Engine
    • Security Level: Jimmy
    • Labels:
      None
    • gh.sprint.customfield.default.name:
      ZK 8.5.2 S2

      Description

      binding listbox within (not yet opened) bandbox causes uncaught TypeError: Cannot set property 'scrollTop' of null
      at init.setSelInView_ (zk.wpd:38712)
      at Function._set2 (zk.wpd:11067)
      at init.setter.func (zk.wpd:19291)
      at init.zk.Widget.zk.$extends.set (zk.wpd:19319)
      at Object.setAttr (zk.wpd:26935)
      at doProcess (zk.wpd:25462)
      at doCmdsNow (zk.wpd:25561)
      at Object._doCmds (zk.wpd:25889)
      at Object.afterResponse (zk.wpd:26386)
      at XMLHttpRequest._onResponseReady (zk.wpd:26250)

      Seems to be a side-effect of ROD, because after opening bandbox once, error does not appear again. We analyzed, that before opening bandbox, zul.sel.Listbox.setSelinView() is called for a listbox widget, which does not yet have a corresponding DOM element (this.ebody is undefined).

        Issue Links

          Activity

          Hide
          fse fse added a comment -

          temporarily I fixed issue by overwriting setSelInView_()

          {{ <attribute w:name="setSelInView_">
          function () {
          if (this.ebody)

          { // ZK-3932 this.$setSelInView_(); //call the original method }

          }
          </attribute>}}

          Show
          fse fse added a comment - temporarily I fixed issue by overwriting setSelInView_() {{ <attribute w:name="setSelInView_"> function () { if (this.ebody) { // ZK-3932 this.$setSelInView_(); //call the original method } } </attribute>}}
          Hide
          MDuchemin MDuchemin added a comment - - edited

          Based on the stacktrace, would be a racing condition between the Listbox initialization.
          Meshwidget._bindDomNode and invocation of listbox.setSelectedIndex(int index)

          Ebody is the internal state tracking the body node of the listbox. should be set at any point after initialization.

          Meshwidget _bindDomNode initialize ebody
          https://github.com/zkoss/zk/blob/master/zul/src/archive/web/js/zul/mesh/MeshWidget.js#L909

          _setSelInView is triggered by calling setSelectedIndex manually or through model data change
          However in these cases, the smartUpdate call for selInView_ should be done in the same AU request.

          example:
          click on the button to set selectedIndex while the bandbox has never been opened yet

          zul

          <zk>
          	<div apply="ListModelListboxComposer">
          	<bandbox id="bb">
          		<bandpopup id="bpp">
          		 <custom-attributes org.zkoss.zul.listbox.rod="true"/>
          		</bandpopup>
          	</bandbox>
          	</div>
          	<button id="btn" label="click to set selected index on lb"/>
          </zk>
          

          java

          import org.zkoss.zk.ui.Component;
          import org.zkoss.zk.ui.select.SelectorComposer;
          import org.zkoss.zk.ui.select.annotation.Listen;
          import org.zkoss.zk.ui.select.annotation.Wire;
          import org.zkoss.zk.ui.util.Clients;
          import org.zkoss.zul.Bandpopup;
          import org.zkoss.zul.ListModelList;
          import org.zkoss.zul.Listbox;
          
          public class ListModelListboxComposer extends SelectorComposer {
          
          	private Listbox lb = new Listbox();
          	
          	@Wire
          	private Bandpopup bpp;
          	private ListModelList model = new ListModelList<>();
          	
          	@Override
          	public void doAfterCompose(Component comp) throws Exception {
          		super.doAfterCompose(comp);
          		for (int i = 0; i < 1000; i++) {
          			model.add("row"+i);
          		}
          		lb.setModel(model);
          		lb.setHeight("500px");
          		bpp.appendChild(lb);
          	}
          	
          	@Listen("onClick=#btn")
          	public void doBtnClick(){
          		Clients.showNotification("test");
          		lb.setSelectedIndex(800);
          	}
          	
          }
          
          
          Show
          MDuchemin MDuchemin added a comment - - edited Based on the stacktrace, would be a racing condition between the Listbox initialization. Meshwidget._bindDomNode and invocation of listbox.setSelectedIndex(int index) Ebody is the internal state tracking the body node of the listbox. should be set at any point after initialization. Meshwidget _bindDomNode initialize ebody https://github.com/zkoss/zk/blob/master/zul/src/archive/web/js/zul/mesh/MeshWidget.js#L909 _setSelInView is triggered by calling setSelectedIndex manually or through model data change However in these cases, the smartUpdate call for selInView_ should be done in the same AU request. example: click on the button to set selectedIndex while the bandbox has never been opened yet zul <zk> <div apply= "ListModelListboxComposer" > <bandbox id= "bb" > <bandpopup id= "bpp" > <custom-attributes org.zkoss.zul.listbox.rod= " true " /> </bandpopup> </bandbox> </div> <button id= "btn" label= "click to set selected index on lb" /> </zk> java import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.select.SelectorComposer; import org.zkoss.zk.ui.select.annotation.Listen; import org.zkoss.zk.ui.select.annotation.Wire; import org.zkoss.zk.ui.util.Clients; import org.zkoss.zul.Bandpopup; import org.zkoss.zul.ListModelList; import org.zkoss.zul.Listbox; public class ListModelListboxComposer extends SelectorComposer { private Listbox lb = new Listbox(); @Wire private Bandpopup bpp; private ListModelList model = new ListModelList<>(); @Override public void doAfterCompose(Component comp) throws Exception { super .doAfterCompose(comp); for ( int i = 0; i < 1000; i++) { model.add( "row" +i); } lb.setModel(model); lb.setHeight( "500px" ); bpp.appendChild(lb); } @Listen( "onClick=#btn" ) public void doBtnClick(){ Clients.showNotification( "test" ); lb.setSelectedIndex(800); } }
          Hide
          MDuchemin MDuchemin added a comment -

          <custom-attributes org.zkoss.zul.client.rod="false"/>
          disabling client render on demand on the bandbox prevents the issue

          <bandbox id="bb">
          <custom-attributes org.zkoss.zul.client.rod="false" />
          <bandpopup id="bpp">

          Show
          MDuchemin MDuchemin added a comment - <custom-attributes org.zkoss.zul.client.rod="false"/> disabling client render on demand on the bandbox prevents the issue <bandbox id="bb"> <custom-attributes org.zkoss.zul.client.rod="false" /> <bandpopup id="bpp">
          Hide
          MDuchemin MDuchemin added a comment -

          If the listbox uses a Listmodel as data source, then selection should be handled on model using model.addToSelection()

          Show
          MDuchemin MDuchemin added a comment - If the listbox uses a Listmodel as data source, then selection should be handled on model using model.addToSelection()
          Hide
          rudyhuang rudyhuang added a comment -

          Fixed since 2018/06/29

          Show
          rudyhuang rudyhuang added a comment - Fixed since 2018/06/29

            People

            • Assignee:
              CharlesQiu CharlesQiu
              Reporter:
              fse fse
            • Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Time Tracking

                Estimated:
                Original Estimate - 1 day
                1d
                Remaining:
                Time Spent - 2 hours, 30 minutes Remaining Estimate - 5 hours, 30 minutes
                5h 30m
                Logged:
                Time Spent - 2 hours, 30 minutes Remaining Estimate - 5 hours, 30 minutes
                2h 30m

                  Agile