how to render table body only in jsf dataTable - jsf

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>

Related

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

How does reRender behave if table is not rendered

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 :).

Datatable with rows of inputs

I have a datatable that generates rows of text inputs and selection lists and when I submit the values are null. I realize this is because jsf is generating separate random ID's for each input. I really need the data by rows and then parse out what I need. Any suggestions?:
<h:dataTable id="returnableItems" value="#{returnableItemsBean.orderCustomerFamilyItems}" var="item" styleClass="data stripeTable center">
<h:column>
<f:facet name="header">Item Number</f:facet>
<h:outputText id="itemNum" value="#{item.itemNum}"/>
</h:column>
<h:column>
<f:facet name="header">Description</f:facet>
<h:outputText value="#{item.itemDescription}"/>
</h:column>
<h:column>
<f:facet name="header">Original Quantity</f:facet>
<h:outputText value="#{item.originalQuantity}"/>
</h:column>
<h:column>
<f:facet name="header">Remaining Quantity</f:facet>
<h:outputText value="#{item.eligibleQuantity}"/>
</h:column>
<h:column>
<f:facet name="header">Quantity For Return</f:facet>
<h:panelGrid styleClass="stepper">
<span class="ns ui-stepper">
<input id="returnQuantity" type="text" name="returnQuantity" size="2" autocomplete="off" class="ui-stepper-textbox" value="0" />
<button type="button" name="ns_button_1_0" value="" class="ui-stepper-plus" onclick="setMaxVal(this,#{item.eligibleQuantity});">+</button>
<button type="button" name="ns_button_2_0" value="" class="ui-stepper-minus">-</button>
</span>
</h:panelGrid>
</h:column>
<h:column>
<f:facet name="header">Reason for Return</f:facet>
<h:selectOneMenu id="returnReason" value="#{returnableItemsBean.orderReason.ordReasonCode}">
<f:selectItems value="#{returnableItemsBean.orderReasons}"/>
<f:converter converterId="orderReasonConverter"/>
</h:selectOneMenu>
</h:column>
<h:column>
<f:facet name="header">Return/Replacement</f:facet>
<h:selectOneMenu id="returnOption">
<f:selectItem itemLabel="Option" itemValue=""/>
<f:selectItem itemLabel="Return" itemValue="return"/>
<f:selectItem itemLabel="Replacement" itemValue="replacement"/>
</h:selectOneMenu>
</h:column>
</h:dataTable>
I fail to understand why you use HTML input and buttons and not JSF ones in your form. Use <h:inputText> and <h:commandButton> instead, and bind their values to a property in your backing bean. The whole table should be inside a <h:form> ... </h:form> tag, of course.
Also, your input should probably be bound to a property of the "item" variable, like you do for output. If not, each row will have an input bound to the same property of your backing bean.
Are you using JSP, or Facelets ?
jsf is generating separate random ID's for each input
The IDs are not random; h:dataTable is a NamingContainer and manages its childrens clientIds so they become unique (a requirement of the HTML spec). JSF: working with component IDs (id vs clientId).
The straight HTML you have added will be difficult to integrate with the JSF model-view-presenter framework. It would be better to stick to JSF controls. This code shows how you can manipulate client-side field values using JavaScript and a custom TLD function:
<h:dataTable value="#{rowDataBean.data}" var="row">
<h:column>
<f:facet name="header">
<h:outputText value="product" />
</f:facet>
<h:outputText value="#{row.name}" />
</h:column>
<h:column id="column2">
<f:facet name="header">
<h:outputText value="quantity" />
</f:facet>
<h:inputText id="quantityCount" value="#{row.quantity}" />
<h:commandButton value="+"
onclick="increment('#{id:clientId('quantityCount')}'); return false;" />
</h:column>
</h:dataTable>
The invoked JavaScript:
function increment(id) {
//TODO: error handling
var textField = document.getElementById(id);
var value = textField.value;
value++;
textField.value = value;
}
If you are using Facelets instead of JSPs, you will need to define the function in a Facelets tag library.

Resources