How does reRender behave if table is not rendered - jsf

I was just implementing a crude functionality using jsf+richfaces and came across this situation, so putting this to the open forum for some answers.
I have a text field and rich:dataTable inside a form. When value changes in textField, table data is populated and table is supposed to be reRendered with latest data.
Now the point in question : What if I have rendered condition on dataTable saying render this table if list of values is not-null/non-empty? So for the 1st time when screen appears, list is null/empty and hence table is not rendered, as and when I modify textField, values are populated and reRender on table is fired but as a whole table does not exist.
Is there a way to solve this behaviour? If I reload the page, yes table definitely appears :)
Here is the sample code for this :
<h:form id="userSearchForm" prependId="false">
<h:inputText value="#{ldapSearch.searchString}">
<a4j:support event="onkeyup" ignoreDupResponses="true" ajaxSingle="true" reRender="usersTable"
requestDelay="50" actionListener="#{ldapSearch.searchUser}"/>
</h:inputText>
<rich:dataTable id="usersTable"
rendered="#{not empty ldapSearch.users}"
value="#{ldapSearch.users}" var="user">
<rich:column sortable="false" label="Name">
<f:facet name="header">
<h:outputText value="Name"/>
</f:facet>
<h:outputText title="#{user.displayName}" value="#{user.displayName}"/>
</rich:column>
</rich:dataTable>
</h:form>

I solve this issue by surrounding the dataTable with some component that is always rendered, and then reRendering that component instead. For example:
<h:form id="userSearchForm" prependId="false">
<h:inputText value="#{ldapSearch.searchString}">
<a4j:support event="onkeyup" ignoreDupResponses="true" ajaxSingle="true" reRender="divUsersTable"
requestDelay="50" actionListener="#{ldapSearch.searchUser}"/>
</h:inputText>
<s:div id="divUsersTable">
<rich:dataTable id="usersTable"
rendered="#{not empty ldapSearch.users}"
value="#{ldapSearch.users}" var="user">
<rich:column sortable="false" label="Name">
<f:facet name="header">
<h:outputText value="Name"/>
</f:facet>
<h:outputText title="#{user.displayName}" value="#{user.displayName}"/>
</rich:column>
</rich:dataTable>
</s:div>
</h:form>

The problem is that you can't rerender something that has not been rendered in the first time. My solution is to play with the display attribute of the component style.
<rich:dataTable id="usersTable"
style="display:#{not empty ldapSearch.users? 'inline' : 'none'}"
value="#{ldapSearch.users}" var="user">
<!-- your columns -->
</rich:dataTable>
In that way, I can rerender the table with no problems :).

Related

how to render table body only in jsf dataTable

When using a JSF dataTable, is it possible to only render the table body? I know it is possible with richfaces with render="table#body", but I can't use it.
This is my code example. The table gets rerendered after a keyup event is fired. The problem with this is, everytime this happens the inputText where this event is fired loses focus and needs to be reselected manually. Since it is located in the table header, rendering the body only could fix this behaviour.
<h:dataTable id="dataTable" value="#{myBean.employeeList}" var="data">
<h:column>
<f:facet name="header">Firstname<br/>
<h:inputText id="searchFirstname" value="#{myBean.searchStringFirstname}" >
<f:ajax listener="#{myBean.searchStringKeyUpListener}" event="keyup" render="dataTable" />
</h:inputText>
</f:facet>
#{data.person.firstname}
</h:column>
<h:column>
<f:facet name="header">Lastname<br/>
<h:inputText id="searchLastname" value="#{myBean.searchStringLastname}"> </h:inputText>
</f:facet>
#{data.person.lastname}
</h:column>
</h:dataTable>

outputText and inputText in f:facet of rich:column doesn't work - JSF

I'm trying to achieve external filtering using rich:dataTable which has sorting ability.
Here's what I have tried:
<rich:column sortBy="#{data.name}" id="name" filterMethod="#myBean.filter}">
<f:facet name="header">
<h:outputText value="Name" />
<h:inputText value="#{myBean.currentName}"
id="nameFilterInput" onclick="Event.stop(event)" onkeypress="searchNameOnEnter(event, this);">
<a4j:support event="onkeyup" reRender="dataTable , ds"
ignoreDupResponses="true" requestDelay="700" />
</h:inputText>
</f:facet>
<h:outputText value="#{data.name}" />
</rich:column>
Problem: The input text field is overwriting the output text (the header name)
I've tried using h:panelGroup inside the f:facet, but the problem is the sort icon is rendered in the third row seperately.
What am I missing here?
Any help would be great.
Updated: #Christophe Roussy, here's the screenshot
As seen the inputText is overwriting the outputText.
Update 2: I saw a post here: https://community.jboss.org/thread/13046 which explains to use <f:facet name="filter"> for inputText, but that seems to work only for rich:extendedDataTable.
Any way to make it work with rich:dataTable?
The <f:facet> can have only one child. Wrap them in a <h:panelGroup>.
<f:facet name="header">
<h:panelGroup>
<h:outputText ... />
<h:inputText ... />
</h:panelGroup>
</f:facet>

navigating to an anchor when editing a row in datable with jsf

(Using jsf-2)
I have a dataTable with one column which can be edited:
<h:column>
<f:facet name="header">
<h:outputText value="Label" style="font-weight: bold">
</h:outputText>
</f:facet>
<h:inputText value="#{m.author2displayed}" rendered="#{m.editable}" size="10"/>
<h:outputText value="#{m.author2displayed}" rendered="#{not m.editable}"/>
<h:commandButton value="save edits" rendered="#{m.editable}" onclick="submit()" action ="#{finalCheckBean.saveedits()}"/>
</h:column>
When I click on "save edits", we stay on the same view and that's the desired effect (finalCheckBean.saveedits() returns null).
Problem: the browser scrolls all back to the top of the page, whereas I'd like that the page stays displayed at the level of the row just edited. How can I achieve that?
If you're already using JSF2, just bring in some ajax magic using <f:ajax> in the command button. Wrap the to-be-executed and rendered components in a common component and reference it in execute and render of <f:ajax>.
<h:column>
<f:facet name="header">
<h:outputText value="Label" style="font-weight: bold" />
</f:facet>
<h:panelGroup id="author2displayed">
<h:inputText value="#{m.author2displayed}" rendered="#{m.editable}" size="10"/>
<h:outputText value="#{m.author2displayed}" rendered="#{not m.editable}"/>
<h:commandButton value="save edits" rendered="#{m.editable}" onclick="submit()" action="#{finalCheckBean.saveedits()}">
<f:ajax execute="author2displayed" render="author2displayed" />
</h:commandButton>
</h:panelGroup>
</h:column>
This way the scroll position will remain unchanged (provided that you still return null or void from the action method).

JSF: creating datatable based on user input text and gathering info from a perticular row selected by radio button

I have a page where I ask the user to input a value into a inputText box. Based on the entered value I create a datetable with information from my database. One of the columns in the datatable is a selectOneRadio therefore each row has its own radio button. The user should then be able to select one of the radio buttons and then click a commandbutton (which is the footer of the datatable) that will obtain which row is selected based on which radio button is selected. The problem that I am having is upon the button click the backing bean method isn't being called. This issue only happens when i create the table after going to the page. if i hard code a value to cause the datatable to exist at the creation of the page this problem does not happen. I'm not completely sure but I believe this problem is happening because the datatable rendered is initially set to false and for some reason this is effecting either the binding or the valueChangeListener some how.
This is the jsf
<h:panelGrid columns="3">
<h:outputLabel for="searchByContrId" value="Company Code: " />
<h:inputText id="searchByContrId" value="#{applContAdminB.searchContrId}">
</h:inputText>
<h:commandButton type="submit" value="Search" id="submitSearch" action="#{applContAdminB.getEmployeesByContrId}" />
</h:panelGrid>
<br />
<h:outputText rendered="#{applContAdminB.contrIdEntered}" value="Current Administrator: " />
<h:outputText value="#{applContAdminB.adminName}" />
<h:dataTable id="empTable" var="loc" rendered="#{applContAdminB.contrIdEntered}" value="#{applContAdminB.employeesListModel}" binding="#{applContAdminB.htmlDataTable}">
<h:column>
<h:selectOneRadio onclick="updateRadioButtons(this);" valueChangeListener="#{applContAdminB.setSelectedRow}">
<f:selectItem itemValue="null" itemLabel="" />
</h:selectOneRadio>
</h:column>
<h:column>
<f:facet name="header">Employee Name</f:facet>
<h:outputText value="#{loc.empName}" />
</h:column>
<h:column>
<f:facet name="header">Employee Email</f:facet>
<h:outputText value="#{loc.empEmail}" />
</h:column>
<h:column>
<f:facet name="header">Status</f:facet>
<h:outputText value="#{loc.userStatus}" />
</h:column>
<f:facet name="footer">
<h:panelGrid columns="2">
<h:commandButton type="submit" id="transferRights-submit" value="Transfer Rights" action="#{applContAdminB.adjustAdminUser}" />
</h:panelGrid>
</facet>
</h:dataTable>
you answered your own question. this is a weakness in using rendered with ajax. i had a similar issue with a navigation widget i had that toggled the attribute that rendered was bound to via ajax. no manner of magic i could muster would get the invisible panel to render while hiding the panel that was initially rendered. you might try just hiding the div via javascript and when your ajax returns twiddle the "display" attribute of the div(s) accordingly. that's how i solved it. it's unfortunate, but i could not find an alternate solution that was desirable. – him

<a4j:commandbutton> action is only invoked on second click

I want to submit a data table on a button click, but that action is not called on the first click. Here is my code:
<h:panelGrid id="addToThisDepartmentPanel">
<h:outputText value="#{messageDataBean.message}" rendered="#{messageDataBean.isSuccess eq false}" style="color:red" id="addToThisDepartmentMessage"/>
<h:form>
<h:dataTable value="#{systemResultViewUtil.systemUserDetailDataBeansList}" var="departmentdetail" id="addToThisDepartmentDataTable" rendered="#{systemResultViewUtil.systemUserDetailDataBeansList.size() gt 0}">
<h:column>
<f:facet name="header">
Name
</f:facet>
<h:outputText value="#{departmentdetail.name}" style="text-align: left;padding-right: 120px" />
</h:column>
<h:column>
<f:facet name="header">
Current Department
</f:facet>
<h:outputText value="#{departmentdetail.depName}" style="text-align: left;padding-right: 120px" />
</h:column>
<h:column>
<f:facet name="header">
Add To This
</f:facet>
<h:selectBooleanCheckbox value="#{departmentdetail.cheked}" style="text-align: left;padding-right: 120px"/>
</h:column>
</h:dataTable>
<a4j:commandButton oncomplete="if(#{messageDataBean.isSuccess eq true}){ closeAddToThisDepartmentDialog()}" value="Add TO This Department" action="#{departmentServiceBean.addEmployeeToThisDepartment}" id="addToThisDepartmentButton"
render=":addToThisDepartmentMessage :message" execute=":addToThisDepartmentDataTable" />
</h:form>
</h:panelGrid>
The problem is that on the second click my <a4j:commandButton> action is called. But it is not called on the first click.
Any ideas?
This problem is known as JSF spec issue 790. If you ajax-render some content which in turn contains a <h:form>, then its view state will get lost, which causes that the 1st action inside that form won't invoke anything. On the ajax response of the first action, the form will get new view state and thus any subsequent actions will succeed.
This is scheduled to be fixed for the upcoming JSF 2.2. But right now with JSF 2.0/2.1 you have to introduce a workaround. You first need to give the <h:form> a fixed ID which is yourFormId in the below example:
<h:panelGrid id="addToThisDepartmentPanel">
...
<h:form id="yourFormId">
...
Then you need to reference it in the render attribute as well:
<f:ajax ... render=":addToThisDepartmentPanel :yourFormId" />
The same story applies to <a4j:xxx> components.
<a4j:commandButton ... render=":addToThisDepartmentPanel :yourFormId" />
See also:
h:commandButton/h:commandLink does not work on first click, works only on second click
Communication in JSF 2.0 - Ajax rendering of content which contains another form

Resources