request scoped dataTable problem with synchronization of dat
ncollette Sep 22, 2008 11:24 AMI have the weirdest thing happening to me in a rich:dataTable. Here's the situation: I have a table of users, and I have an action button to massEnable/massDisable them. So naturally I added a select column on the table so that I could select multiple users. The problem is that when I select them then try to mass enable the users, it acts like I didn't select anyone. After debugging for awhile, I found out what it's doing, but I have no idea how to fix it. If anyone has had similar trouble or knows what I'm doing wrong I would greatly appreciate it. Here's what I found happens: The backing bean is request scoped, the page loads, and let's say 4 user objects are returned with addresses 1-4. Then when the action is performed, a new request scoped backing bean for users is instantiated, and 4 new user objects are fetched from the database with addresses 5-8, then the setSelected methods are called on the "old" user objects addresses 1-4. So naturally when the action method enableUsers is called, it can't find the selected objects, because it checks the newly fetched objects 5-8. any ideas?
Interestingly, if I use h:dataTable or t:dataTable, instead of calling setSelected on 1-4, it correctly calls setSelected on the newly fetched 5-8, and operation is as expected. This is why I'm posting, because it seems to be a bug.
I'm using facelets.
I'm using richFaces 3.2.2, though I've also tried 3.2.1
Here's the .jspx code:
<?xml version="1.0" encoding="ISO-8859-1" ?> <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:a4j="http://richfaces.org/a4j" xmlns:t="http://myfaces.apache.org/tomahawk" xmlns:rich="http://richfaces.org/rich" version="2.0"> <ui:composition template="/template.jspx"> <ui:param name="bean" value="#{userBean}" /> <ui:param name="onLoad" value='doOnLoad()' /> <ui:define name="urlTitle"> <ui:insert name="urlTitles">Summary of Users Template</ui:insert> </ui:define> <ui:define name="script"> <script type="text/javascript"> /* <![CDATA[ */ function doOnLoad() { document.getElementById('filterGridForm:userTable:inputBoxForLoginName').focus(); } function submitMethod (event) { var keycode; if (window.event) { keycode = window.event.keyCode; } else if (event) { keycode = event.which; } else { return true; } if (keycode == 13) { document.getElementById('filterGridForm:filterSubmitButton').click(); return false; } else { return true; } } function hidePopup () { popup = document.getElementById("78"); if (null != popup) { var browser=navigator.appName; var b_version=navigator.appVersion; var version=parseFloat(b_version); if ((browser=="Netscape")|| (browser=="Microsoft Internet Explorer" && version>=7)) { popup.setAttribute("style", "visibility: hidden"); } else { popup.style.cssText="visibility: hidden; height: 0px; width: 0px;"; } } } function popupClipped(theComponent) { var closeButton = document.createElement("button"); var browser=navigator.appName; var b_version=navigator.appVersion; var version=parseFloat(b_version); openDiv = document.getElementById("78"); if (openDiv == null)/*it wasn't found*/ { openDiv = document.createElement("div"); } openDiv.innerHTML = theComponent.childNodes.item(1).nodeValue + "<br />" + "<br />"; openDiv.setAttribute("id", "78"); if ((browser=="Netscape")|| (browser=="Microsoft Internet Explorer" && version>=7)) { closeButton.setAttribute("id", "closeButton");; closeButton.setAttribute("onclick", "hidePopup()"); openDiv.setAttribute("style", "position: absolute; left: 100px; top: 300px; display: table; text-align: center; padding: 20px; background: #ffde00; border: 2px solid #00FF00;"); } else { closeButton.id="closeButton"; closeButton.attachEvent("onclick",hidePopup); openDiv.style.cssText="position: absolute; left: 100px; top: 300px; display: table; text-align: center; padding: 20px; background: #ffde00; border: 2px solid #00FF00;"; } closeButton.innerHTML="close";; openDiv.appendChild(closeButton); document.body.appendChild(openDiv); } /* ]]> */ </script> </ui:define> <!-- menu section --> <!-- <ui:define name="menu"> <h:form id="menuForm"> <div id="menuContainer"> <ul id="menuSub"> <li> <h:commandLink id="connection" action="CONNECTION" value="#{isuite['nav.admin.connection']}" immediate="true"> </h:commandLink> </li> <li> <h:commandLink action="MESSAGES" id="messages" value="#{isuite['nav.admin.messages']}" immediate="true"> </h:commandLink> </li> <li> <h:commandLink action="LOGS" id="logs" value="#{isuite['nav.admin.logs']}" immediate="true"> </h:commandLink> </li> <li class="selected"> <h:commandLink action="USERS" id="users" value="#{isuite['nav.admin.users']}" immediate="true"> </h:commandLink> </li> <li> <h:outputLink id="helpLink" styleClass="last" value="help.jspx" target="blank"> <f:param name="pageTitleKey" value="title.user.summary" /> <h:outputText id="helpText" value="#{isuite['sub.help']}" /> </h:outputLink> </li> </ul> </div> </h:form> </ui:define> --> <ui:define name="content"> <div id="content"> <div id="container"> <ui:define name="title"> <ui:insert name="titles"> <div id="title"> <h:outputText id="theTitle" value="User Summary" /> </div> </ui:insert> </ui:define> <h:form id="filterGridForm"> <div id="filter"> <table> <tr> <td class="filterTitle"> <h:outputLabel styleClass="filterTitle" id="filterLabel" value="Roles Filter" /> </td> <td> <div class="filterCheckBoxesAndButtonsWrapper"> <t:selectManyCheckbox styleClass="horizontalCheckBoxes" id="roles" layout="lineDirection" layoutWidth="2" value="#{userBean.roles}"> <f:selectItems value="#{userBean.allRoles}" /> </t:selectManyCheckbox> <h:commandButton id="filterSubmitButton" value="#{isuite['submit']}" styleClass="btnWithOurStyle" action="#{userBean.changeFilterSetting}" /> <h:commandButton id="filterClearButton" value="#{isuite['reset']}" styleClass="btnWithOurStyle" action="#{userBean.resetFilterSetting}" /> </div> </td> </tr> </table> </div> <div id="gridContainer"> <h:outputText id="ifThereAreNoUsers" rendered="#{empty userBean.users}" value="#{isuite['users.noUsers']}" /> <rich:dataTable id="userTable" rows="10" value="#{userBean.users}" var="aParticularUser" rowBandingInterval="1"> <rich:column styleClass="gridFirstColumn selectColumn"> <f:facet name="header" id="selectHeader"> <h:panelGroup> <div class="gridHeaderTitle"> <h:outputText value="#{isuite['select']}" /> </div> <div class="gridSpaceWhereFilterDoesNotExist"> <h:inputText disabled="true" class="gridSpacingHiddenInput" /> </div> </h:panelGroup> </f:facet> <h:selectBooleanCheckbox id="userSelected" value="#{aParticularUser.selected}" /> </rich:column> <rich:column styleClass="editColumn"> <f:facet name="header" id="editHeader"> <h:panelGroup> <div class="gridHeaderTitle"> <h:outputText value="#{isuite['edit']}" /> </div> <div class="gridSpaceWhereFilterDoesNotExist"> <h:inputText disabled="true" class="gridSpacingHiddenInput" /> </div> </h:panelGroup> </f:facet> <h:commandButton id="userEditButton" value="" action="#{userBean.editThese}" styleClass="buttonEditImage"> <f:setPropertyActionListener target="#{userBean.theUser}" value="#{aParticularUser}" /> </h:commandButton> </rich:column> <rich:column> <f:facet name="header" id="loginNameHeader"> <h:panelGroup> <div class="gridHeaderTitle"> <h:outputText value="#{isuite['user.loginName']}" /> </div> <div class="gridFilter"> <h:inputText id="inputBoxForLoginName" onkeypress="submitMethod(event)" value="#{userBean.userFilter.loginName}" /> </div> </h:panelGroup> </f:facet> <div class="gridDataClipperWrapper"> <h:outputText value="#{aParticularUser.loginName}" /> </div> </rich:column> <rich:column> <f:facet name="header" id="firstNameHeader"> <h:panelGroup> <div class="gridHeaderTitle"> <h:outputText value="#{isuite['user.firstName']}" /> </div> <div class="gridFilter"> <h:inputText id="inputBoxForFirstName" onkeypress="submitMethod(event)" value="#{userBean.userFilter.firstName}" /> </div> </h:panelGroup> </f:facet> <div class="gridDataClipperWrapper"> <h:outputText value="#{aParticularUser.firstName}" /> </div> </rich:column> <rich:column> <f:facet name="header" id="lastNameHeader"> <h:panelGroup> <div class="gridHeaderTitle"> <h:outputText value="#{isuite['user.lastName']}" /> </div> <div class="gridFilter"> <h:inputText id="inputBoxForLastName" onkeypress="submitMethod(event)" value="#{userBean.userFilter.lastName}" /> </div> </h:panelGroup> </f:facet> <div class="gridDataClipperWrapper"> <h:outputText value="#{aParticularUser.lastName}" /> </div> </rich:column> <rich:column> <f:facet name="header" id="userRolesForGrid"> <h:panelGroup> <div class="gridHeaderTitle"> <h:outputText value="#{isuite['user.roles']}" /> </div> <div class="gridSpaceWhereFilterDoesNotExist"> <h:inputText disabled="true" class="gridSpacingHiddenInput" /> </div> </h:panelGroup> </f:facet> <div class="gridDataClipperWrapper"> <h:outputText value="#{aParticularUser.roles}"> <f:converter converterId="roleConverter" /> </h:outputText> </div> </rich:column> <rich:column> <f:facet name="header" id="enabledHeader"> <h:panelGroup> <div class="gridHeaderTitle"> <h:outputText value="#{isuite['user.enabled']}" /> </div> <div class="gridFilter"> <h:inputText id="filterEnabled" maxlength="5" onkeypress="submitMethod(event)" value="#{userBean.userFilter.enabled}" converter="booleanConverter" /> </div> </h:panelGroup> </f:facet> <h:outputText value="#{aParticularUser.enabled}" /> </rich:column> </rich:dataTable> <ui:insert name="buttonsOfFunctionality"> <h:commandButton id="addNewUser" value="#{isuite['user.add']}" styleClass="btnWithOurStyle" action="#{userBean.addNewUser}"> </h:commandButton> <h:commandButton id="enableUsers" value="#{isuite['user.enableUsers']}" styleClass="btnWithOurStyle" action="#{userBean.enableUsers}"> </h:commandButton> <h:commandButton id="disableUsers" value="#{isuite['user.disableUsers']}" styleClass="btnWithOurStyle" action="#{userBean.disableUsers}"> </h:commandButton> <h:commandButton id="export" value="#{isuite['export']}" rendered="#{! empty userBean.users}" styleClass="btnWithOurStyle" action="#{userBean.exportUsers}" title="#{isuite['export']}" /> <t:inputFileUpload id="userFileUpload" value="#{userBean.file}" storage="file" /> <h:commandButton id="import" value="#{isuite['import']}" styleClass="btnWithOurStyle" action="#{userBean.importUsers}" title="#{isuite['import']}" /> </ui:insert> </div> </h:form> <div style="" /> </div> </div> </ui:define> </ui:composition> </jsp:root>