1 Reply Latest reply on Nov 14, 2008 12:30 PM by nbelaevski

    ReRender comboBox with display:none

    douglasi22

      A bizarre behavior occurs when you have a comboBox inside a containing JSF component (rich:panel, rich:dataTable, h:panelGrid, etc.) that has its style set to display:none. If you try to reRender the comboBox or any other JSF component that contains the comboBox while the style is set to display:none, then when you display the containing JSF component the comboBox does not work properly. In one case when I clicked on the comboBox it would set the width of my body tag to 148px. The comboBox will also not close once it is opened as can be seen with my example below.

      I have found a workaround. With the onclick attribute I call a JavaScript function that gives an absolute position to the containing JSF component and moves it to the left -2000px and then displays the component. Since the element is -2000px off to the left of the screen the user does not see it. After the onclick is done, the reRender takes place. Then with the oncomplete event, which takes place after the reRender occurs, I undo the style manipulation that occurred in the onclick event. Here are the two JavaScript functions I use to accomplish this:

       function comboBoxHack() {
       var gridStyle = $('myForm:panelGrid').style;
       gridStyle.position = 'absolute';
       gridStyle.left = '-2000px';
       gridStyle.display = '';
       }
       function undoComboBoxHack() {
       var gridStyle = $('myForm:panelGrid').style;
       gridStyle.display = 'none';
       gridStyle.position = '';
       gridStyle.left = '';
       }
      


      I do not necessarily like this workaround as it makes maintenance harder. So if there is something I can do to make it work without the hack that I created, please let me know. But I am guessing that this is a bug with the comboBox that will need fixed in a future release.

      Here is the example code. My JSP:
      <?xml version="1.0" encoding="ISO-8859-1" ?>
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
       xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
       xmlns:a4j="http://richfaces.org/a4j" xmlns:rich="http://richfaces.org/rich">
       <f:view>
       <h:form id="myForm">
       <h:panelGrid id="panelGrid" style="display:none" columns="4">
       <h:outputLabel for="name" value="Name" />
       <h:inputText id="name" value="#{testController.infoBeans[0].name}"/>
       <h:outputLabel for="place" value="Place" />
       <rich:comboBox id="place" value="#{testController.infoBeans[0].place}"
       suggestionValues="#{testController.places}"/>
       </h:panelGrid>
       <br />
       <div>
       <a4j:commandButton value="Call ReRender on ComboBox" reRender="place"/>
       <a4j:commandButton value="Display Grid with Bug"
       onclick="$('myForm:panelGrid').style.display = ''"/>
       </div>
       <div>
       <a4j:commandButton value="Call ReRender on ComboBox with Fix" reRender="place"
       onclick="comboBoxHack();" oncomplete="undoComboBoxHack();"/>
       <a4j:commandButton value="Display Grid without Bug"
       onclick="$('myForm:panelGrid').style.display = ''"/>
       </div>
       </h:form>
      
       <script type="text/javascript">
       //<![CDATA[
       function comboBoxHack() {
       var gridStyle = $('myForm:panelGrid').style;
       gridStyle.position = 'absolute';
       gridStyle.left = '-2000px';
       gridStyle.display = '';
       }
       function undoComboBoxHack() {
       var gridStyle = $('myForm:panelGrid').style;
       gridStyle.display = 'none';
       gridStyle.position = '';
       gridStyle.left = '';
       }
       //]]>
       </script>
       </f:view>
      </jsp:root>
      


      My backing bean:
      package test;
      
      import java.io.Serializable;
      import java.util.ArrayList;
      import java.util.List;
      
      import org.richfaces.component.html.HtmlDataTable;
      
      public class TestController implements Serializable
      {
       private static final long serialVersionUID = 1L;
      
       private List<InfoBean> infoBeans;
       private List<String> places;
       private transient HtmlDataTable dataTable;
      
       public TestController()
       {
       super();
       populateInfoBeans();
      
       this.places = new ArrayList<String>();
       this.places.add("Alaska");
       this.places.add("Colorado");
       this.places.add("Delaware");
       this.places.add("Florida");
       this.places.add("Georgia");
       }
       public void populateInfoBeans()
       {
       this.infoBeans = new ArrayList<InfoBean>();
       this.infoBeans.add(new InfoBean("Alice", "Alaska"));
       this.infoBeans.add(new InfoBean("Collin", "Colorado"));
       this.infoBeans.add(new InfoBean("Del", "Delaware"));
       this.infoBeans.add(new InfoBean("Flo", "Florida"));
       this.infoBeans.add(new InfoBean("George", "Georgia"));
       }
       public List<InfoBean> getInfoBeans()
       {
       return this.infoBeans;
       }
       public void setInfoBeans(List<InfoBean> infoBeans)
       {
       this.infoBeans = infoBeans;
       }
       public List<String> getPlaces()
       {
       return this.places;
       }
       public void setPlaces(List<String> places)
       {
       this.places = places;
       }
       public HtmlDataTable getDataTable()
       {
       return this.dataTable;
       }
       public void setDataTable(HtmlDataTable dataTable)
       {
       this.dataTable = dataTable;
       }
      
       public class InfoBean implements Serializable
       {
       private static final long serialVersionUID = 1L;
      
       private String name;
       private String place;
      
       public InfoBean(String name, String place)
       {
       super();
       this.name = name;
       this.place = place;
       }
       public String getName()
       {
       return this.name;
       }
       public void setName(String name)
       {
       this.name = name;
       }
       public String getPlace()
       {
       return this.place;
       }
       public void setPlace(String place)
       {
       this.place = place;
       }
       }
      }
      


      Code in faces-config.xml:
       <managed-bean>
       <managed-bean-name>testController</managed-bean-name>
       <managed-bean-class>test.TestController</managed-bean-class>
       <managed-bean-scope>session</managed-bean-scope>
       </managed-bean>
      


      To see the bug, when the page loads up, first click on the Call ReRender on ComboBox button and then click the Display Grid with Bug. When you click on the comboBox, the popup will never go away.

      To see the workaround, hit Ctrl+F5 to do a hard refresh. Then click the Call ReRender on ComboBox with Fix button followed by clicking the Display Grid without Bug button. Now the comboBox should behave correctly.

      FYI, I am using RichFaces 3.2.2 on GlassFish 9.1.