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.
Related
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" ... />
my data table
<h:form>
<h:dataTable value="#{testController.items}" var="item" border="0">
<h:column>
<h:outputText value="#{item.name}"/>
</h:column>
</h:dataTable>
</h:form>
i'm using a modal to hold my form, the modal contains this commandbutton
<p:commandButton styleclass="btn btn-primary" action="#{testController.create}" oncomplete="handleComplete(xhr, status, args)" />
handleComplete function:
function handleComplete(xhr, status, args) {
if(args.validationFailed) {
alert("failed");
}else{
$('#test-modal').modal('hide');
// Do something here to reload the datatable to add the newly created item
}
}
im using jsf 2 and i also imported primefaces
You can use <p:remoteCommand> to generate a JavaScript function which invokes a JSF command action.
<h:form>
<h:dataTable id="table" value="#{testController.items}" var="item" border="0">
<h:column>
<h:outputText value="#{item.name}"/>
</h:column>
</h:dataTable>
<p:remoteCommand name="updateTable" action="#{testController.update}" update="table" />
</h:form>
This can be invoked as follows:
function handleComplete(xhr, status, args) {
if (args.validationFailed) {
alert("failed");
} else {
$('#test-modal').modal('hide');
updateTable();
}
}
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";
}
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.
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.