Im trying to display a simple table with an #Entity infos using the following tag-libs:
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
Here's the mapped entity attribute, a boolean:
#NotNull
#Column(name = "ACTIVE", columnDefinition = "BIT", length = 1)
private boolean active;
//... getters and setters
public boolean getActive() {
return active;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active= active;
}
ps.: by debugging the backing bean, im getting the desired list.
Here's my .xhtml (jsf page) snippet:
<ui:repeat var="u" value="#{usersList}">
<tr>
<td>#{u.name}</td>
<td>#{u.login}</td>
<td>#{u.email}</td>
<td>
<c:choose>
<c:when test="${u.active}">
<span style="color: green" class="glyphicon glyphicon-ok"></span>
</c:when>
<c:otherwise>
<span style="color: red"
class="glyphicon glyphicon-remove"></span>
</c:otherwise>
</c:choose>
</td>
</tr>
</c:when>
</ui:repeat>
Altough the list is not empty, the empty message is being shown, and no row is displayed.
If i force the row displaying, removing the conditional rendering, i get the following error:
java.lang.IllegalArgumentException: Cannot convert 1 of type class java.lang.Long to class java.lang.Boolean
for the property active.
I've tried a few solutions before asking, like these:
How does Java expression language resolve boolean attributes? (in JSF 1.2)
javax.el.PropertyNotFoundException when trying to resolve Boolean properties in EL
Update 1: reviewing my code, i realised i was empty testing an object, not a list, updating my snippet also, so, the conditional on the rows displaying its ok now, but the active property issue, still throwing the error.
The problem is that JSF tags (e.g. ui:repeat) are evaluated in a different (later) phase then JSTL tags (e.g. c:when). Therefore the values of your user list are just not available when the c:when statement is evaluated. Sometimes this results in a weird behaviour so that it looks like the values are available. Have a look at this answer to get some details.
You should use the rendered attribute of some JSF component:
<c:choose>
<c:when test="${u.active}">
<span style="color: green" class="glyphicon glyphicon-ok"></span>
</c:when>
<c:otherwise>
<span style="color: red" class="glyphicon glyphicon-remove"></span>
</c:otherwise>
</c:choose>
turns into:
<h:panelGroup rendered="#{u.active}">
<span style="color: green" class="glyphicon glyphicon-ok"></span>
</h:panelGroup>
<h:panelGroup rendered="#{not u.active}">
<span style="color: red" class="glyphicon glyphicon-remove"></span>
</h:panelGroup>
You can also use it for values like this:
<h:outputText rendered="#{u.active}" value="#{u.name}" />
See also:
c:choose not working in JSF
JSTL in JSF2 Facelets… makes sense?
Related
This question already has answers here:
How to perform JSF validation in actionListener or action method?
(5 answers)
Validate email format and uniqueness against DB
(1 answer)
Closed 2 years ago.
I've run into a problem validating a certain input (email) before submitting the whole object..
jsf looks like this:
<h:panelGroup id="reportingRecipientTable">
<table cellspacing="0" class="table no-footer" width="100%" style="word-wrap: break-word;">
<thead>
<tr>
<th><h:inputText p:type="email" p:placeholder="Add a valid Email address" value="#{viewModel.reportingRecipient}"
styleClass="form-control #{component.valid ? '' : 'has-errors'}">
<f:ajax execute="#this" />
</h:inputText></th>
<th class="col-sm-3">
<div class="text-center">
<h:commandLink immediate="true" style="width:95px" styleClass="btn btn-default" actionListener="#{viewModel.addReportingRecipient}">
<i class="icon-plus" /> Add
<f:ajax render="reportingRecipientTable" />
</h:commandLink>
</div>
</th>
</tr>
</thead>
<tbody>
<c:forEach items="#{viewModel.getReportingRecipients()}" var="reportingRecipient">
<tr>
<td><h:outputText required="true" value="#{reportingRecipient}" styleClass="form-control" /></td>
<td class="col-sm-3">
<div class="text-center">
<h:commandLink styleClass="btn btn-default" style="width:95px" actionListener="#{viewModel.removeReportingRecipient(reportingRecipient)}">
<i class="icon-trash" /> Remove
<f:ajax render="reportingRecipientTable" />
</h:commandLink>
</div>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</h:panelGroup>
As you see, I'm adding a (supposedly valid) email address to a tablerow before submitting everything:
public void addReportingRecipient() {
if (!Utils.isNullOrBlank(reportingRecipient) && reportingRecipient.matches("(^.*#.*\\..*$)")) {
getReportingRecipients().add(reportingRecipient);
this.reportingRecipient = "";
} else{ //not valid
}
}
Well, this works (email is only added if it matches the pattern), missing one little detail: I want to mark the "inputText" as invalid (styleClass="form-control #{component.valid ? '' : 'has-errors'}") if it isnt a valid email address. adding a validator to the inputText like this:
<h:inputText p:placeholder="Add a valid Email address" validator = "#{emailValidator.isCorrectEmail}" value="#{viewModel.reportingRecipient}"
styleClass="form-control #{component.valid ? '' : 'has-errors'}">
does only work if i hit the final submit button - but i want to mark the field invalid the moment the user tries to add an invalid email.
Anyone got an idea/some hints?
Your code example of using a validator is the right way to go. Don't validate in business methods.
<h:inputText p:type="email" p:placeholder="Add a valid Email address" value="#{viewModel.reportingRecipient}"
styleClass="form-control #{component.valid ? '' : 'has-errors'}">
<f:ajax execute="#this" />
</h:inputText></th>
Does correctly use #{component.valid...} to style the component. But it does not work on the ajax call because you do not (re)render the input on the ajax event. The default is for an f:ajax is render="#none", so nothing is updated. Adding a render="#this" or if you also want to display a message some other id will make it work.
The fact that it works on 'Remove' button is because the ajax call on the input has already updated the state and you do render the complete table. So the input is (re)renderd.
See also
Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes
Validator is called but error message is not displayed
Highlight an inputText in JSF when a validation error occurs
I was working with Spring and Thymeleaf when I've encountered the following problem: I need a Form object, which has a list of items (Item) as attribute; I'm using an html form to print the Name of the Item, and to generate a checkbox for each Item (any checkbox's value is the corresponding item's id).
The form works correctly, sending to the Controller a list of item's ids corresponding to the checked checkboxes.
However, now, I'm trying to check some checkbox upon the occurrence of a condition (if itemIds, which is a list, contains the current item's id). For that I'm using:
th:checked="${#lists.contains(itemIds, item.id)}"/>
But it doesn't work (checkbox are all unchecked).
I tried also with a "dummy test":
th:checked="${1 == 1 ? 'checked' : ''}"/>
But, again, all the checkbox remain unchecked; the "checked" attribute is ignored as you can see in this example of the rendered HTML:
<input type="checkbox" value="12" class="chkCheckBox" id="ids1" name="ids">
What am I doing wrong? What am I missing here?
form.html
<form th:action="#{${uriBase}+'/new/' + ${date}}"
method="POST" th:object="${form}">
<div class="table-responsive">
<table class="table">
<thead class=" text-primary">
<tr>
<th>Name</th>
<th><input type="checkbox" th:id="checkAll"/>Check</th>
</tr>
</thead>
<tbody>
<tr th:each="item : ${items}">
<td th:text="${item.name}"></td>
<td>
<input type="checkbox" th:field="*{ids}"
th:value="${item.id}" th:class="chkCheckBox"
th:checked="${#lists.contains(itemIds, item.id)}"/>
</td>
</tr>
</tbody>
</table>
<button type="submit" class="btn btn-primary pull-right">Submit</button>
<div class="clearfix"></div>
</div>
</form>
Form class
public class Form implements Serializable {
private List<Long> ids;
//getter and setter
}
Thank you in advance.
I have been struggling with this as well. If you use the th:field it will override the checked and value options, as Xaltotun mentions, because it is trying to get the value and checked option from the field/form.
If you change it to th:name it should work how you want...
But this forum seems to be helpful for doing it with th:feild.
As far as I understand there are 2 issues in your post:
The dummy example is incorrect.
th:checked="${1 == 1 ? 'checked' : ''}"
In fact the value must true or false not 'checked'. If you try with
th:checked="${1 == 1}"/>
It will work.
If you set th:field="*{ids}" then the checkbox should be trying to get the value from the field item.ids and will not use the "th:checked" or "th:value" properties. Does the item has the field ids?
<c:forEach items="${list }" var="element">
<c:if test='${not empty element.radioelement}'>
<input type="radio" name="${element.name }" id="${element.id }" >
<label for="${element.id }"></label>
</c:if>
<c:if test='${not empty element.divelement}'>
<div> </div>
</c:if>
<c:if test='${not empty element.breakelement}'>
<br />
</c:if>
</c:forEach>
This is the jstl code I'm trying to find out if it works.
The list is filled with the objects of the class "tyle" which I made myself. These contain the following properties:
private String radioelement, divelement, breakelement, name, id;
I made sure they all have setters and getters.
I'm trying to make it work so that depending on which property isn't null, that piece of html will be written. (a radiobutton incase the string radioelement isn't null and so forth untill the list ends)
I'm wondering if this will work this way cus if it does I'll probably have a logical fault in my code. As it is now it only registers the breaks and makes any divelement also into a radio.
I have a users list page which holds the users in a p:dataTable and in each row I have an update button that shows a p:dialog popup.
The page and the dialog is managed in view scope (implemented in Spring).
When I press the editUserButton in the main page the popup appears with all data and then I type an invalid string into the fields email and username. The validation message appears, but the picklist is not populated with any value.
What could be the problem?
This is the main page (users list) snippet code:
<ui:composition>
<f:view id="bodyView">
<div id="content_body">
<ui:include src="editUserDialog.xhtml"/>
<h:form id="usersListForm">
<table width="85%" align="center">
<tr>
<td>
<p:dataTable id="usersList" var="user"
value="#{usersController.usersList}"
selectionMode="single"
rowKey="#{user.userId}">
<p:columnGroup type="header">
<p:row>
...
<p:column rowspan="2" headerText="Users"/>
...
</p:row>
</p:columnGroup>
...
<p:column id="users" >
<p:commandLink id="editUserButton" oncomplete="addEditUserConfirmation.show()" actionListener="#{addEditUserController.selectionListener}"
update=":addEditCustomerDialogForm:dialogContent">
<f:attribute value="#{user}" name="selectedUser" />
</p:commandLink>
</p:column>
</p:dataTable>
</td>
</tr>
</table>
<br/>
</h:form>
</div>
</f:view>
This is the p:dialog code:
<ui:composition>
<h:form id="addEditUserDialogForm">
<p:dialog id="addEditUserDialog" severity="alert" widgetVar="addEditUserConfirmation" draggable="true" modal="true"
resizable="false" >
<p:outputPanel id="dialogContent">
<div>
<table cellpadding="5">
<tr>
<td>
<p:inputText value="#{addEditUserController.addEditCustomerBean.userName}"
maxlength="250" size="50" label="user name" id="userName">
<f:validator validatorId="UsernameValidator"/>
</p:inputText>
<p:message for="userName"/>
</td>
</tr>
<tr>
<td>
<p:inputText value="#{addEditUserController.addEditCustomerBean.email}"
maxlength="50" size="50" label="E-mail" id="email">
<f:validator validatorId="EmailValidator"/>
</p:inputText>
<p:message for="email"/>
</td>
</tr>
</table>
<table cellpadding="5">
<tr>
<td>
<p:pickList id="customersList" iconOnly="true"
value="#{addEditUserController.customersList}" var="customer"
itemValue="#{customer.value}" itemLabel="#{customer.label}"/>
</td>
</tr>
</table>
</div>
<div align="right">
<p:commandButton value="#{isNewUser ? 'add' : 'update'}" id="updateUserButton"
actionListener="#{addEditUserController.persistUser}"
update="dialogContent"
styleClass="fiftyone-default-button"
oncomplete="handleRequest(xhr, status, args)"/>
</div>
</p:outputPanel>
</p:dialog>
</h:form>
<script type="text/javascript">
function handleRequest(xhr, status, args) {
if(!(args.validationFailed && args.validationFailed == true)) {
addEditUserConfirmation.hide();
}
}
</script>
This is the backing bean code:
import org.primefaces.model.DualListModel;
import javax.annotation.PostConstruct;
import javax.faces.event.ActionEvent;
import java.util.List;
public class AddEditUserController {
private AddEditCustomerBean addEditCustomerBean;
private DualListModel<LabelValueBean> customersList;
// ... constructor getters and setters
public void selectionListener(ActionEvent event) throws Exception {
selectedUser = event.getComponent().getAttributes().get("selectedUser");
// some code
AddEditCustomerBean = new AddEditCustomerBean();
// some code
customersList = getSomeCustomersDualListModel()
}
public void persistUser() throws Exception {
// save user to DB
}
}
First thing I'd do would be to make sure that the method selectionListener is being called (either put a break-point on it or print something and check in the console later).
If it is, you must check if the variable customersList is being updated correctly, if it's not, you probably have a problem with bean scoping.
In your sample code it isn't clear how you are setting the scope for the backing bean, so I assume you're doing it on Spring's XML config file.
Make sure you really have the backing bean in the view scope, by inspecting the contents of the view map: FacesContext.getCurrentInstance().getViewRoot().getViewMap().
Hope it helps!
This is an old question, but I also encountered this issue recently, and now being helpless. Let's see the p:pickList:
<td>
<p:pickList id="customersList" iconOnly="true"
value="#{addEditUserController.customersList}" var="customer"
itemValue="#{customer.value}" itemLabel="#{customer.label}"/>
</td>
We know the [var="customer"] is an iterator, but when validation error happens, this var is assigned to String type, it's odd. When you close this popup then re-populate it again, you will get an error, messages like this: no property label(value) on type of String... the customer var now is a String, so it has no value nor label property.
For now, I use a tricky way, it won't work out always, it depends on your code:
Assume that the value and label are unique, set customersList type of List String, customersList binds the label, find the value of the label when submit at the backend; Why this way can avoid re-populate exception, that's because the iterator is always type of String, no matter validation error occurs or not.
Hope this can help the need.
I receive the exception
Failed to convert property value of
type [java.lang.String] to required
type [beans.Product] for property
product; nested exception is
java.lang.IllegalArgumentException:
Cannot convert value of type
[java.lang.String] to required type
[beans.Product] for property product:
no matching editors or conversion
strategy found
in the Errors errors object even before my DetailProductValidator starts validating through the validate method.
I don't understand why Spring does that. I don't have any input field that is mapped directly to the product property/object. I just use the product object's properties in the jsp. For example, I use:
<form:options items="${dpBackObj.product.colorMap}"/>
<!-- or -->
${dpBackObj.product.priceInDollars}
but I never use:
<form:input path="product"/>
Can anyone please explain why this happens? And maybe inform me of a simple solution?
The bean configuration for the controller is:
<!-- DETAIL PRODUCT FORM CONTROLLER -->
<bean id="productDetailFormController" name="/detail.htm /addToCart.htm"
class="detailProduct.DetailProductFormController">
<property name="sessionForm" value="true" />
<property name="commandName" value="dpBackObj" />
<property name="commandClass" value="detailProduct.DetailProductBackingObject" />
<property name="validator">
<bean class="detailProduct.DetailProductValidator" />
</property>
<property name="formView" value="detail" />
<property name="successView" value="redirect:/viewCart.htm" />
<property name="cartService" ref="cartServiceImpl"/>
</bean>
The backing object for the DetailProductFormController is:
public class DetailProductBackingObject {
private String quantityOverflowError;
private Product product;
private int quantity;
private ShoppingCart shoppingCart;
private long sizeId;
private long colorId;
public DetailProductBackingObject() {
this.product = new Product();
this.sizeId = -1;
this.colorId = -1;
}
//getters and setters
}
If you need some other info, I will provide. I am using Spring 2.5.5.
Kind Regards,
Despot
EDIT1 (due to request from axtavt):
<form:form method="post" commandName="dpBackObj">
<table width="730" border="0" cellspacing="0" cellpadding="0">
<c:if test="${!empty dpBackObj.quantityOverflowError}">
<tr>
<td>
<c:out value="${dpBackObj.quantityOverflowError}"/>
</td>
</tr>
</c:if>
<spring:bind path="dpBackObj.*">
<c:if test="${not empty status.errorMessages}">
<div class="val-summary text-error" id="errorDivId">
<div style="" class="val-summary text-error" id="errorDivId">
<fmt:message key="detail.error.header"/>
<ul>
<c:forEach items="${status.errorMessages}" var="error">
<li><c:out value="${error}"/></li>
</c:forEach>
</ul>
</div>
</div>
</c:if>
</spring:bind>
<tr>
<td width="310" align="left" valign="top">
<img src="${imagesPath}/${dpBackObj.product.largeImageUrl}" alt="${dpBackObj.product.description}" />
</td>
<td width="420" align="left" valign="top">
<div id="tls_detPName">
<c:out value="${dpBackObj.product.name}"></c:out>
</div>
<div >
<strong class="numeric">${dpBackObj.product.priceInDollars}</strong>
</div>
<div id="tls_detPDescLong">
${dpBackObj.product.largeDescription}
<br />
</div>
<div >
<table cellpadding="2" border="0">
<tr>
<td align="right">
<label for="p_sizes" class="label"><fmt:message key="viewCart.Size"/></label>
</td>
<td>
<form:select path="sizeId" >
<form:option value="-1" label="x"/>
<form:options items="${dpBackObj.product.sizeMap}"/>
</form:select>
</td>
</tr>
<tr>
<td align="right">
<label for="p_colors" class="label"><fmt:message key="viewCart.Color"/></label>
</td>
<td>
<form:select path="colorId" >
<form:option value="-1" label="y"/>
<form:options items="${dpBackObj.product.colorMap}"/>
</form:select>
</td>
</tr>
</table>
</div>
<div id="tls_addToCart">
<div >
<label for="quantityId" class="label"><fmt:message key="viewCart.Quantity"/>:</label>
<form:input path="quantity" onkeypress="return checkForNumber(this, event)" maxlength="10" size="3" id="quantityId" cssClass="textbox-center"/>
<input type="image" name="addToCartButtonName" src="${imagesPath}/addToCartBtn.jpg" />
</div>
</div>
</td>
</tr>
</table>
</form:form>
EDIT2 (due to JacobM's request):
This is my Validator:
public class DetailProductValidator implements Validator {
public boolean supports(Class clazz) {
return DetailProductBackingObject.class.equals(clazz);
}
public void validate(Object obj, Errors errors) {
DetailProductBackingObject detailProductBackingObject = (DetailProductBackingObject) obj;
if (detailProductBackingObject.getSizeId() == -1) {
errors.rejectValue("sizeId", "error.detail.jsp.choose.size", null, "Input size.");
}
}
}
When I reach the line DetailProductBackingObject detailProductBackingObject = I already have the error.
The converting of the request parameters to the backing object properties happens in http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/web/servlet/mvc/BaseCommandController.html . This is what Spring says about the conversion:
Populating using request parameters
and PropertyEditors: Upon receiving a
request, any BaseCommandController
will attempt to fill the command
object using the request parameters.
This is done using the typical and
well-known JavaBeans property
notation. When a request parameter
named 'firstName' exists, the
framework will attempt to call
setFirstName([value]) passing the
value of the parameter. Nested
properties are of course supported.
For instance a parameter named
'address.city' will result in a
getAddress().setCity([value]) call on
the command class.
It's important to realise that you are
not limited to String arguments in
your JavaBeans. Using the
PropertyEditor-notion as supplied by
the java.beans package, you will be
able to transform Strings to Objects
and the other way around. For instance
setLocale(Locale loc) is perfectly
possible for a request parameter named
locale having a value of en, as long
as you register the appropriate
PropertyEditor in the Controller (see
initBinder() for more information on
that matter.
Validators: After the controller has
successfully populated the command
object with parameters from the
request, it will use any configured
validators to validate the object.
Validation results will be put in a
Errors object which can be used in a
View to render any input problems.
Since I can't see anything wrong with the form, the only possible reason I can imagine is that you have a parameter named product in the URL of your form page.
If so, you can change your URLs or use DataBinder.setDisallowedFields() to disable the attempt to bind that parameter.