Using h:selectBooleanCheckbox to delete multiple rows in JSF datatable - jsf

I have followed the instruction as per the posts How to select multiple rows of <h:dataTable> with <h:selectBooleanCheckbox> and Using <h:selectBooleanCheckbox> with Map in a paginated <p:dataTable> throws NullPointerException
on how to delete multiple rows from a datatable. However, the checked Map object is not being populated with the the selected values. When I debug the application it is always empty.
Here is my code:
applicantSearch.xhtml
<ui:composition template="/WEB-INF/templates/main.xhtml">
<ui:define name="menu">
<ui:include src="/protected/views/menu.xhtml"/>
</ui:define>
<ui:define name="content">
<h:outputScript target="body">
formatMyTable();
</h:outputScript>
<h3>Search for Applicants</h3>
<h:form id="searchForm" class="form-search">
<h:panelGroup id="results" class="table-responsive">
<h:outputText id="informationMessage"
value="#{applicantSearchBacking.infoMessage}"
rendered="#{applicantSearchBacking.infoMessage ne null}"
class="informationMessage"/>
<div class="btn-toolbar">
<h:commandButton value="Delete Selected" onclick="if (! confirm('Are you sure you want to delete the selected applicants?')) return false" action="#{applicantSearchBacking.removeSelectedApplicants}" class="btn btn-danger btn-large pull-right">
<f:ajax render=":searchForm:results :searchForm:messages" onevent="formatMyTable"
/>
</h:commandButton>
</div>
<br/>
<h:dataTable value="#{applicantSearchBacking.applicantList}"
var="currentApplicant" styleClass="table table-hover table-condensed table-bordered"
>
<h:column>
<f:facet name="header">
Applicant ID
</f:facet>
#{currentApplicant.applicantId}
</h:column>
<h:column>
<f:facet name="header">
First Name
</f:facet>
#{currentApplicant.firstName}
</h:column>
<h:column>
<f:facet name="header">
Middle Name
</f:facet>
#{currentApplicant.middleName}
</h:column>
<h:column>
<f:facet name="header">
Last Name
</f:facet>
#{currentApplicant.lastName}
</h:column>
<h:column>
<f:facet name="header">
Actions
</f:facet>
<!-- User Access control section <c:if test=""> -->
<h:link value="Edit" outcome="#{applicantSearchBacking.editApplicant()}" class="btn btn-primary btn-sm">
<f:param name="myApplicantId" value="#{currentApplicant.applicantId}">
</f:param>
</h:link>
<!-- </c:if> -->
<!-- <c:if test=""> -->
<h:selectBooleanCheckbox id="del_checkbox" value="#{applicantSearchBacking.checked[currentApplicant.applicantId]}">
</h:selectBooleanCheckbox>
<!-- </c:if> -->
</h:column>
</h:dataTable>
</h:panelGroup>
<h:messages id="messages" class="errorMessage"/>
</h:form>
</ui:define>
applicantSearchBacking.java
private Map<Integer, Boolean> checked = new HashMap<>();
public void removeSelectedApplicants()
{
try {
List<Applicant> applicantsToDelete = new ArrayList<>();
for (Applicant applicant : applicantList) {
Boolean itemChecked = checked.get((applicant.getApplicantId()));
if (itemChecked !=null && itemChecked) {
applicantsToDelete.add(applicant);
}
}
applicantManager.removeSelectedApplicants(applicantsToDelete);
if (!checked.isEmpty())
infoMessage = "Applicant(s) deleted successfully";
checked.clear();
}

This construct will only work if exactly the same data model is preserved for the postback. So, if your bean is #RequestScoped, then it must be creating exactly the same applicantList inside #PostConstruct as it was when the form was displayed. Otherwise, you need to make the bean #ViewScoped. In any case, I assume that the getter method of applicantList doesn't do any business logic, but just solely returns the property.
See also:
Why JSF calls getters multiple times
How to choose the right bean scope?
commandButton/commandLink/ajax action/listener method not invoked or input value not updated - point 4
As per your question update, there's another potential mistake which may cause this construct to fail:
<f:ajax render=":searchForm:results :searchForm:messages" onevent="formatMyTable" />
The execute of <f:ajax> is here unspecified and uses then thus the default of #this. You need to explicitly specifiy #form in order to process the entire form on submit, otherwise only the parent component (the command button itself) would be processed.
<f:ajax execute="#form" ... />

Related

JSF Method is called always two times

Hi I have a jsf datatabel using view scope, which allows sorting and pagination.
My problem is, that my BackingBean method for sorting is always called two times which would not be a big problem if not for sorting ascending/descending when sorting for the same row (which makes it obsolete).
Any ideas how to solve this problem? I've already read several blocks about this problem, but non was helping me in my case yet…
I also tried to change it to request scope but this just made my pagination disappear…
This is the BackingBean Methode which is only called from my facelet link:
/**
* Changing sorting of list of events by columns.
*
* #param event
* ActionListener for the sorting field.
*/
public void sort(String sortingAttribute) {
System.out.println("you called sort: " + ++x);
if (sortField.equalsIgnoreCase(sortingAttribute)) {
boolean sortAscHelp = (sortAsc) ? false : true;
sortAsc = sortAscHelp;
} else {
sortField = sortingAttribute;
}
try {
events = (eventListType.equalsIgnoreCase("search")) ?EventManager.getSearchResults(searchTitle, searchDate, searchLocation, sortField, sortAsc, offset, limit) : EventManager.getEventList(eventListType, offset, limit, sortField, sortAsc);
} catch (DatabaseException e) {
FacesContext fcxt = FacesContext.getCurrentInstance();
fcxt.addMessage(component.getClientId(),
new FacesMessage(e.toString()));
logger.error("Error while loading the sorted list of searched events.");
}
}
And here comes my facelet:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html">
<ui:composition template="../../templates/basicTemplate.xhtml">
<ui:define name="metadata">
<f:metadata>
<f:viewParam name="title" value="#{listEventsBean.searchTitle}"/>
<f:viewParam name="location" value="#{listEventsBean.searchLocation}"/>
<f:viewParam name="date" value="#{listEventsBean.searchDate}"/>
<f:viewParam name="eventListType" value="#{listEventsBean.eventListType}"/>
<f:viewParam name="page" value="#{listEventsBean.page}"/>
<f:viewParam name="sorting" value="#{listEventsBean.sortField}"/>
<f:viewAction action="#{listEventsBean.init}"/>
</f:metadata>
</ui:define>
<ui:define name="content">
<h:form>
<p style="color:#808080; font-weight:bold; font-size:large">#{msgs.listEvents_events}</p>
<br/>
<h:outputText style="color:green" value="#{msgs.listEvents_deleted}" rendered="#{listEventsBean.deleted}"/>
<h:dataTable id="eventTable" value="#{listEventsBean.getEvents()}" var="event" binding="#{listEventsBean.component}">
<h:column>
<f:facet name="header">
<h:commandLink value="#{msgs.listEvents_title}" action="#{listEventsBean.sort('title')}">
<f:attribute name="sortField" value="title"/>
</h:commandLink>
</f:facet>
<h:outputText value="#{event.title}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:commandLink value="#{msgs.listEvents_dateStart}" action="#{listEventsBean.sort('startofevent')}">
<f:attribute name="sortField" value="startOfEvent"/>
</h:commandLink>
</f:facet>
<h:outputText value="#{event.startOfEvent}">
<f:convertDateTime pattern="#{msgs.longDate}"/>
</h:outputText>
</h:column>
<h:column>
<f:facet name="header">
<h:commandLink value="#{msgs.listEvents_dateEnd}" action="#{listEventsBean.sort('endofevent')}">
<f:attribute name="sortField" value="endOfEvent"/>
</h:commandLink>
</f:facet>
<h:outputText value="#{event.endOfEvent}">
<f:convertDateTime pattern="#{msgs.longDate}"/>
</h:outputText>
</h:column>
<h:column>
<f:facet name="header">
<h:commandLink value="#{msgs.listEvents_price}" action="#{listEventsBean.sort('ticketprice')}">
</h:commandLink>
</f:facet>
<h:outputText value="#{event.ticketPrice}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{msgs.listEvents_action}"/>
</f:facet>
<h:button id="showDetails" value="#{msgs.listEvents_showDetails}"
outcome="showEvent">
<f:param name="eventID" value="#{event.eventID}"/>
</h:button>
<h:commandButton id="deleteEvent" value="#{msgs.listEvents_delete}"
action="#{listEventsBean.deleteEvent(event.eventID)}"
rendered="#{sessionBean.ld.systemAdmin}"
onclick="return confirm('#{msgs.listEvents_deleteMsg}')"/>
</h:column>
</h:dataTable>
<h:outputText style="color:blue" value="#{msgs.listEvents_emptyResult}" rendered="#{listEventsBean.notEmpty}"/>
<br />
<h:outputLink id="backToSearchLink" value="#{request.contextPath}/facelets/allUsers/searchEvents.xhtml" rendered="#{listEventsBean.notEmpty}">
<h:outputText value="#{msgs.listEvents_searchAgain}"/>
</h:outputLink>
<ui:repeat id="paginationEvent" var="p" value="#{listEventsBean.getPageNumbers()}">
<h:outputLink value="#{request.contextPath}/facelets/allUsers/listEvents.xhtml">
<h:outputText value="#{p.toString()}" />
<f:param name="page" value="#{p.toString()}" />
<f:param name="sorting" value="#{listEventsBean.sortField}"/>
<f:param name="eventListType" value="#{listEventsBean.eventListType}" />
</h:outputLink>
</ui:repeat>
</h:form>
</ui:define>
</ui:composition>
</ui:composition>
Damn it! I just found my bug!
I still had a binding attached to my dataTable (beginning of dataTable).
Because of my view scope binding causes errors. One seems to be to call my method in dataTable twice (Tanks to BalusC for this info). Deleted this and added messages by rendering them as h:outputText.
I am still open for any suggestions how to change my scope to request without loosing my pagination or how to add messages from my BackingBean differently to my application without rendering h:outputText and bindings.

navigation when bean returns objects

Beginner question concerning changing the information in a view (and not going to a different .xhtml page). My .xhtml displays a datatable (which shows a list of people), but I want the user to be able to narrow the amount of info displayed by typing in the start of someones name into an inputtext and then clicking the commandbutton. Both the commandbutton and the datatable execute the same bean method, but if the inputtext has data the sql uses Like (this uses jdbc). My form is below, the problem is that I get an "Unable to find matching navigation case with from-view-id" because my managed bean returns a list of objects, not "success" or "failure". Also, the whole form seems inefficient. This seems like a fairly common scenario - calling managed bean's method that returns objects and not navigation instructions. How do I get rid of the error messages? Is there a better way to do this?
Here is code:
<h:head>
<h:outputStylesheet library="css" name="table-style.css" />
</h:head>
<h:body>
<h1>MavenWeb</h1>
<h:form>
<h:panelGrid columns="3">
Select a customer:
<h:inputText id="listName" value="#{customer.listName}"
size="20" >
</h:inputText>
<h:commandButton value="Submit"
action="#customer.getCustomerList()}" />
</h:panelGrid>
<h:dataTable value="#{customer.getCustomerList()}" var="c"
styleClass="order-table"
headerClass="order-table-header"
rowClasses="order-table-odd-row,order-table-even-row"
>
<h:column>
<f:facet name="header">
Customer ID
</f:facet>
#{c.customerID}
</h:column>
<h:column>
<f:facet name="header">
Name
</f:facet>
#{c.name}
</h:column>
<h:column>
<f:facet name="header">
Address
</f:facet>
#{c.address}
</h:column>
<h:column>
<f:facet name="header">
Created Date
</f:facet>
#{c.created_date}
</h:column>
</h:dataTable>
</h:form>
</h:body>
First, make sure your managed bean has ViewScope, so only the form values will be affected on every request while you're in the same view. Second, you can add ajax behavior to your <h:commandButton> and render the <h:datatable> with the new values. Third, never put business logic inside your attribute getters, because the JSF framework could make 2 or more calls of those getters (depending on your design).
Using these rules, you can remake your code like this:
#ViewScoped
#ManagedBean
public class Customer {
private String listName;
private List<CustomerDTO> customerList;
public Customer() {
listName = "";
customerList = null; //maybe you can initialize your list here
}
//getters and setters...
//look that this method returns a void (no need to return a navigation rule)
public void fillCustomerList() {
//your method/way to fill the customerList goes here...
//I'll just put a code example
customerList = new ArrayList<CustomerDTO>();
customerList.add(new CustomerDTO(1, "Luiggi Mendoza", "Lima", new Date());
customerList.add(new CustomerDTO(2, "StackOverflow", "Web", new Date());
}
}
The code fragment for your page
<h:form>
<h:panelGrid columns="3">
Select a customer:
<h:inputText id="listName" value="#{customer.listName}" size="20" />
<h:commandButton value="Submit" action="#customer.fillCustomerList}">
<f:ajax execute="#this" render="dtMyDataTable" />
</h:commandButton>
</h:panelGrid>
<h:dataTable id="dtMyDataTable" value="#{customer.customerList}" var="c"
styleClass="order-table"
headerClass="order-table-header"
rowClasses="order-table-odd-row,order-table-even-row">
<h:column>
<f:facet name="header">
Customer ID
</f:facet>
#{c.customerID}
</h:column>
<h:column>
<f:facet name="header">
Name
</f:facet>
#{c.name}
</h:column>
<h:column>
<f:facet name="header">
Address
</f:facet>
#{c.address}
</h:column>
<h:column>
<f:facet name="header">
Created Date
</f:facet>
#{c.created_date}
</h:column>
</h:dataTable>
</h:form>
More info on this matter:
Does view scope bean survive Navigation JSF
Learning JSF2: Ajax in JSF – using f:ajax tag

JSF access to the "var" attribute value from dataTable from jsp

I'm using JSF 1.1. I have a JSP page with a
....
<t:dataTable id="data"
styleClass="scrollerTable"
headerClass="standardTable_Header"
footerClass="standardTable_Header"
columnClasses="col1,col2,col3"
var="product"
value="#{beanProduct.listOfProducts}"
preserveDataModel="false"
rows="10"
>
....
The #{product} has a attribute named state. If its value is "pending", then I want to display a <h:commandButton>, else I display nothing.
How can I get the value of #{product.state} in JSP scriptlet code?
I tried the next:
....
<h:column>
<f:facet name="header">
<h:outputText value="#{messages['list']}" />
</f:facet>
<%
// ----> In this point, I want know the value of "product.state"
FacesContext context = FacesContext.getCurrentInstance();
Application app = context.getApplication();
ValueBinding binding = app.createValueBinding("#{product.state}");
Object valueOfProduct = binding.getValue(context);
String stateProduct = (String)valueOfProduct;
if (stateProduct.equals("pending")) {
%>
<h:panelGrid>
<h:commandButton value="Send" actionListener="#{beanProduct.Item}" action="#{beanProduct.sending">
<f:attribute name="idProduct" value="#{product.id}" />
</h:commandButton>
</h:panelGrid>
<%
}
else {
%>
// Do nothing.
<%
}
%>
</h:column>
</t:dataTable>
But it does not work. How can I achieve this?
You should use "rendered" attribute instead:
<h:column>
<f:facet name="header">
<h:outputText value="#{messages['list']}" />
</f:facet>
<h:commandButton rendered="#{product.pending}" value="Send"
actionListener="#{beanProduct.Item}"
action="#{beanProduct.sending">
<f:attribute name="idProduct" value="#{product.id}" />
</h:commandButton>
</h:column>
Mixing JSF and JSP like this won't work because dataTable var will not be available at the time your embedded code is executed. Also it is not a recommended practice.

how to pass values from jsf-jsp

How can I pass user entered values from/to JSP where I have used JSF as framework? Here is my code:
<h:dataTable id="dt1" value="#{Ack.list}" var="ack" >
<h:column>
<f:facet name="header">
<h:outputText style=""value=" Number" />
</f:facet>
<h:outputText style="" value="#{ack.number}" ></h:outputText>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Acknowledgement"/>
</f:facet>
<h:inputText value="" > </h:inputText>
</h:column>
<h:column>
<h:outputText value=""/>
<h:commandButton action="" value="Submit"></h:commandButton>
</h:column>
</h:dataTable>
I want to enter some value in the textfield provided for "acknowledgement" and click on submit button. How can I send the user entered "acknowledgment" on button click?
First add a property acknowledgement to the class Ack (at least, the class which represents each item of the datatable, as declared in var attribute of the table).
public class Ack {
private String acknowledgement;
// Add/generate getter and setter.
}
Then bind the input field to that.
<h:inputText value="#{ack.acknowledgement}" />
Ensure that the table is already placed inside a <h:form> and I'd also move the command button outside the table, one button is enough. Bind its action to a backing bean method.
<h:form>
<h:dataTable ...>
...
</h:dataTable>
<h:commandButton action="#{Ack.submit}" value="Submit" />
</h:form>
Finally define the method in the bean. At that point, JSF has already set the submitted values. You just have to save them in the DB or something.
public String submit() {
ackDAO.save(list);
return "outcome";
}

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