navigation when bean returns objects - jsf

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

Related

Using h:selectBooleanCheckbox to delete multiple rows in JSF datatable

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" ... />

render column in jsf datatable first time only

as per my requirement I have to show a delete button end of row in datattable but restriction is to show only for first row, not in each row.
how to restrict it
belwo is my datatable
<h:dataTable id="datatable" value="#{relationBean.languageDTOList}" var="lang">
<h:column>
<f:facet name="header"> Relation Type Name</f:facet>
<h:outputText value="#{relationBean.relationName}" />
</h:column>
<h:column>
<f:facet name="header"> Value</f:facet>
<h:inputText />
</h:column>
<h:column>
<f:facet name="header">language</f:facet>
<h:outputText value="#{lang.languageName}" />
</h:column>
<h:column>
<f:facet name="header"> Delete</f:facet>
<p:commandLink rendered="" action="#{relationBean.deleteDataTable}" immediate="true" update="#form" process="#this">
<h:graphicImage value="../images/delete.png" />
<f:setPropertyActionListener target="#{relationBean.deleteId}" value="#{var}" />
</p:commandLink>
</h:column>
Bean.java its showing contents of bean
public List<LanguageDTO> getLanguageDTOList() {
System.out.println("RelationBean:getLanguageDTOList:Enter");
CountryList = new ArrayList<Country>();
try {
CountryList.add(countryService.getCountryByCode(city));
List<LanguageDTO> tempLangDTOlst=new ArrayList<LanguageDTO>();
for (Country lang : CountryList) {
LanguageDTO languageDTO = new LanguageDTO();
for (CountryLanguage CLang : lang.getCountryLanguage()) {
languageDTO = new LanguageDTO();
languageDTO.setLanguageName(CLang.getLanguage().getLanguageName());
languageDTO.setLanguageCode(CLang.getLanguage().getLanguageCode());
System.out.println(CLang.getLanguage().getLanguageName());
tempLangDTOlst.add(languageDTO);
}
}
setLanguageDTOList(tempLangDTOlst);
System.out.println("languageDTOList :"+languageDTOList);
} catch (Exception e) {
e.printStackTrace();
}
//BeanUtils.copyProperties(tempLangDTO,languageDTOList);
System.out.println("--------------------Start -------------");
for (LanguageDTO iterable_element : languageDTOList) {
System.out.println(iterable_element.getLanguageName());
}
System.out.println("-------------------- End -------------");
System.out.println("RelationBean:getLanguageDTOList:Exit");
return languageDTOList;
}
Bind the <h:dataTable> to the view via binding, which will reference an UIData component instance and in the rendered attribute just check if UIData#getRowIndex() equals to 0.
<h:dataTable binding="#{table}" ...>
<h:column>
<p:commandLink ... rendered="#{table.rowIndex eq 0}">
(note: do not bind it to a bean like #{bean.table}! the code is complete as-is)
See also:
How does the 'binding' attribute work in JSF? When and how should it be used?
JSF component binding without bean property
You can test if the current element is the same as the first element of your list:
<p:commandLink rendered="#{lang eq relationBean.languageDTOList.get(0)}"> ...
This would works only if languageDTOList is a List.
If you were using p:dataTable instead of the standard JSF DataTable, you could use the rowIndexVar variable to test if your are at the first iteration.

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";
}

How to send a List from JSF to backing Bean

I am using a Datatable in JSF1.2 to populate the data received from Seam component/ using a List. The data is getting fetched when I use the list. But when, I want to make the Datatable editable so that the value I am changing on the JSF page can be sent back to the Seam Component/ Backing Bean the list is not passing value to the Seam component/Backing Bean.
I have tried but I am unable to pass the list to Seam component/Backing Bean again.
Below is the code.
JSF code:
<h:dataTable value="#{mainbean.findCustomerlist}" var="findCustomerList">
<h:column>
<f:facet name="header">
<h:outputText value="Sr No" />
</f:facet>
<h:outputText value="#{findCustomerList.id}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Company Name" />
</f:facet>
<h:inputText value="#{findCustomerList.companyName}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Account Number" />
</f:facet>
<h:inputText value="#{findCustomerList.accountNumber}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Contact Number" />
</f:facet>
<h:inputText value="#{findCustomerList.contactNumber}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Contact Name" />
</f:facet>
<h:inputText value="#{findCustomerList.contactName}" />
</h:column>
<br></br>
</h:dataTable>
<h:commandButton value="Update" type="submit" action="#{mainbean.modifyCustomer(findCustomerlist)}" />
Seam Component/Backing Bean Code:
private List<Customer> findCustomerlist=null;
public List<Customer> getFindCustomerlist() {
return findCustomerlist;
}
public void setFindCustomerlist(List<Customer> findCustomerlist) {
this.findCustomerlist = findCustomerlist;
}
public void searchCustomer(ActionEvent actionEvent)
{
findCustomerlist=session.findCustomer(customerName);
}
/* The searchCustomer function works fine and it returns the list to the JSF. But when I use the modifyCustomer function to retrieve the value from JSF then it is not working.*/
public void modifyCustomer(List<Customer> findCustomerlist)
{
session.updateCustomer(findCustomerlist);
System.out.println("Inside modifyCustomer");
System.out.println(findCustomerlist.get(0).getCompanyName());
}
I am not sure what Seam is doing about this, but in normal JSF this is unnecessary. Normally, JSF has already updated the list property during update model values phase. You just has to access it as a local bean property. I.e.
<h:commandButton value="Update" type="submit" action="#{mainbean.modifyCustomer}" />
with
public void modifyCustomer()
{
session.updateCustomer(findCustomerlist);
System.out.println("Inside modifyCustomer");
System.out.println(findCustomerlist.get(0).getCompanyName());
}
should already be enough.
You only need to ensure that the same list is preserved by the backing bean. The code which you've shown as far will fail when the bean is request scoped. If you're on JSF 2.0 you could put the bean in view scope. On JSF 1.x you need to either put bean in session scope (not recommended) or to preload the list in bean's constructor or #PostConstruct based on customerName.

Exception thrown while accessing HTML DataTable in backing bean

I am building a simple application in JSF with the CrUD functionality. I am trying to implement edit functionality using the tomahawk component .I am unable to retrieve the selected row in my backing bean.
Here's my JSP file snip:
<t:dataTable id="data"
binding="#{selectOneRowList.dataTable}"
styleClass="scrollerTable"
headerClass="standardTable_Header"
footerClass="standardTable_Header"
rowClasses="standardTable_Row1,standardTable_Row2"
columnClasses="standardTable_Column,standardTable_ColumnCentered,standardTable_Column"
var="car"
value="#{selectOneRowList.list}"
sortColumn="#{selectOneRowList.sortColumn}"
sortAscending="#{selectOneRowList.sortAscending}"
preserveDataModel="false"
preserveSort="true"
preserveRowStates="true"
rows="10"
>
<h:column>
<f:facet name="header">
<h:outputText value="Select"/>
</f:facet>
<t:selectOneRow groupName="selection" id="hugo" value="#{selectOneRowList.selectedRowIndex}"
onchange="submit();" immediate="true"
valueChangeListener="#{selectOneRowList.processRowSelection}"/>
</h:column>
<h:column>
<f:facet name="header">
</f:facet>
<h:outputText value="#{car.id}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Cars" />
</f:facet>
<h:outputText value="#{car.type}" />
</h:column>
<t:column sortable="true">
<f:facet name="header">
<h:outputText value="Color" />
</f:facet>
<h:outputText value="#{car.color}" />
</t:column>
</t:dataTable>
Here's my backing bean SelectOneRowList.java :
public void editCar(ActionEvent event) {
System.out.println("Row number ## " + _selectedRowIndex.toString() + " selected!");
System.out.println("Datatable ::"+ dataTable);
System.out.println("Row Count ::" + dataTable.getRowCount());
dataItem = (SimpleCar) getDataTable().getRowData();
//selectedCar = (SimpleCar) _list.get(Integer.parseInt(_selectedRowIndex.toString()));
selectedCar = (SimpleCar) dataTable.getRowData();
System.out.println(dataTable.getRowData());
}
My DTO{Data Transfer Object} which is SimpleCar.java contains the variables ID, type, color and their respective setters/getters.
The dataItem variable is of type "SimpleCar". The dataTable is of type HTMLDataTable. I am able to get the the first 3 SOP's but the 4th SOP isn't printed. I receive the following exception on the server :
javax.faces.el.EvaluationException: Exception while invoking expression #{selectOneRowList.editCar}
org.apache.myfaces.el.MethodBindingImpl.invoke(MethodBindingImpl.java:156)
javax.faces.component.UICommand.broadcast(UICommand.java:89)
javax.faces.component.UIViewRoot._broadcastForPhase(UIViewRoot.java:97)
javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:171)
org.apache.myfaces.lifecycle.InvokeApplicationExecutor.execute(InvokeApplicationExecutor.java:32)
org.apache.myfaces.lifecycle.LifecycleImpl.executePhase(LifecycleImpl.java:95)
org.apache.myfaces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:70)
javax.faces.webapp.FacesServlet.service(FacesServlet.java:139)
org.apache.myfaces.webapp.filter.ExtensionsFilter.doFilter(ExtensionsFilter.java:341)
On click of the edit button the editCar method in my backing bean is invoked. I need to get the data of the selected row in my backing bean. Why is the exception occurring ?
The above example is taken from the tomawhawk examples WAR distributed on the website. I have gone through many links including the ones on BalusC but none of them have helped.
Regards,
To use DataTable.getRowData() you would have to put the button tied to editCar() within the data table. So, on your JSP would need to add another column, such as:
...
<t:column sortable="true">
<f:facet name="header">
<h:outputText value="Color" />
</f:facet>
<h:outputText value="#{car.color}" />
</t:column>
<t:column sortable="false">
<h:commandButton value="Edit" action="#{selectOneRowList.editCar}" />
</t:column>
</t:dataTable>

Resources