Looking for a away to validate pre-submit in jsf [duplicate] - validation

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

Related

JSF PrimeFace: p repeat ajax update with class not working

totalListSumA is an ArrayList inside java. Inside debug mode, the arraylist work just fine. New value assigned into this list.
When user input a new value in a box, program will recalculate new sum and display inside the code shown below.
<p:inputNumber
class="caseType1"
rendered="#{inputFormTemplateView.allowEdit}"
inputStyle="text-align: center"
minValue="0"
maxValue="99999999"
decimalPlaces="0"
thousandSeparator=""
emptyValue=""
value="#{inputFormView.selectedInputFormDetail.data[dataField]}" >
<p:ajax update="dataField, #{inputForm4_1View.getColTotal()}"/>
<p:ajax update="#(.totalRow3)"></p:ajax>
</p:inputNumber>
<tr>
<td align='center'>Total</td>
<p:repeat var="item" value="#{inputForm4_1View.totalListSumA}" class="totalRow3">
<td class="cell_cal" style='text-align:center;' >
<h:outputLabel
class="totalRow3"
value="#{item}" />
</td>
</p:repeat>
</tr>
I have tried
h:panelGroup id='...'
ui:repeat id='....'
Still the value remain unchanged inside p:repeat. Any method I can try to get and show the latest value inside totalListSumA?
This is wrong
<p:ajax update="dataField, #{inputForm4_1View.getColTotal()}"/>
<p:ajax update="#(.totalRow3)"></p:ajax>
1) Ajax should have event="change" or other events, but most wrong thing is that calling bean method inside update.
2) Use listener="#{inputForm4_1View.getColTotal()}"
3) Don't use 2 same ajaxes.
Solution:
<p:ajax event="change" update="dataField, #(.totalRow3)" listener="#{inputForm4_1View.getColTotal()}"/>
If this doesn't solve your problem, try update form like update="#form" or update="yourFormId"

JSF 2.2 Table conditional rendering not working

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?

p:pickList not fetching data after pressing p:commandButton

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.

SelectOneRadio set time on selection

I've been raking my brain trying to figure this one out. I have a really simple requirement that's turning out to be a very interesting problem.
The requirement is to update a time stamp when the user chooses a selection in a radio button list.
So I have a radio button list:
...
<h:selectOneRadio value="#{mybean.myvalue}" >
<f:selectItem itemLabel="A" itemValue="A"/>
<f:selectItem itemLabel="B" itemValue="B"/>
<f:selectItem itemLabel="C" itemValue="C"/>
<f:selectItem itemLabel="D" itemValue="D"/>
<f:ajax render="timeBox" listener="#{measurements.captureTime('timeBox')}"/>
</h:selectOneRadio>
...
And a text box a little further down the page:
...
<h:outputText id="timeBox" value='#{measurements.timeBox}'>
<f:convertDateTime pattern="HH:mm:ss"/>
</h:outputText>
...
And then in the backing bean I have the listener defined:
...
public void captureTime(String id){
if(id.equals("timeBox"){
timeBox = new Date(System.currentTimeMillis());
}
}
...
But when I change the radio button, the value is not updating. I'm pretty sure this is to do with the various phases of JSF (ie. it's not being updated because of the problem in this post: http://balusc.blogspot.ca/2012/03/reset-non-processed-input-components-on.html) but I'm not entirely sure how to fix it.. I'd really like to avoid including another library if possible.
As always let me know if you need more info and I will be happy to oblige.
Thanks!
Edit
The structure of these components is:
<h:form>
<table>
<tr>
<td>
<h:select.../>
</td>
</tr>
<tr>
<td>
<h:output.../>
</td>
</tr>
</table>
</h:form>
The given construct suggests that you've duplicate components with the same ID. Make sure that you don't actually have duplicate components with the same ID.

JSF2 ajax events not triggered in dynamically included pages

I have a AdminHome.xhtml page which has a dynamic include as below:
<h:form id="masterform">
<table class="DEFTABLE">
<tbody>
<tr>
<td class="CREATESTYLE">Create
<h:selectOneMenu styleClass="SELECTBOX" id="createBox" value="#{adminWindowController.actionSelection}">
<f:ajax event="change" execute=":masterform:workspace" listener="#{adminWindowController.invokeAction}" render=":masterform:workspace :masterform:taskbar createBox"/>
<f:selectItem itemValue="NONE" itemLabel="Select one..."/>
<f:selectItem itemValue="CREATE_ENTITY_DEFINITION" itemLabel="Entity Definition"/>
<f:selectItem itemValue="CREATE_ENTITY_GROUP" itemLabel="Entity Group" />
<f:selectItem itemValue="CREATE_USER" itemLabel="User" />
<f:selectItem itemValue="CREATE_USER_GROUP" itemLabel="User Group" />
</h:selectOneMenu>
</td>
</tr>
</tbody>
</table>
<h:panelGroup id="workspace">
<table class="DEFTABLE">
<tr>
<td class="WSHEIGHT" valign="top">
<ui:include src="#{adminworkspace.workspaceContent}"/>
</td>
</tr>
</table>
</h:panelGroup>
</h:form>
The above include will get page names dynamically during various ajax events triggered on AdminHome.xhtml page.
Below is one of the dynamic pages that gets loaded when the selectOneMenu changes.
<ui:composition>
<h:form id="entdefcreateform">
<h:panelGroup id="entdefpanel">
<table>
</table>
<table cellspacing="0">
<tr>
<ui:repeat value="#{adminEntityDefnController.entDefTabList}" var="tab">
<td class="#{tab == uIUtil.getRequestMapValue('activetab','General') ? 'TABBUTTONCTIVE' : 'TABBUTTON'} ">
<h:commandLink action="#{adminWindowController.TabChange}" style="border: none;">
<f:ajax execute=":masterform:entdefcreateform:entdefpanel" render=":masterform:entdefcreateform:entdefpanel"/>
<f:param name="activetab" value="#{tab}"/>
<h:outputText value="#{tab}"/>
</h:commandLink>
</td>
</ui:repeat>
</tr>
</table>
<table class="TABCONTENTTABLE">
<tr valign="top">
<td class="TABCONTENT">
<ui:include src= "#{adminEntityDefnController.entDefTabTable.get(uIUtil.getRequestMapValue('activetab','General'))}"/>
</td>
</tr>
</table>
</h:panelGroup>
</h:form>
</ui:composition>
In JSF2, <ui:include>s are evaluated during restore view phase, not during render response phase. Therefore, they do not work dynamically (anymore). I have had the same problem after migrating from JSF 1.2 to 2.1.
I got it working by changing the action method of the bean. The trick is to return to the same page that fires the ajax request. I'm using PrimeFaces 2.2.1 and the menu fires in ajax way.
The first problem i see in your code is that you could NOT have 2 <form> : one nested in another.
I guess that's why your events don't fire.
I had the same problem in may code !
BTW BalusC could you explain more precisely what you did by
"The trick is to return to the same page that fires the ajax request. I'm using PrimeFaces 2.2.1 and the menu fires in ajax way"
This is not clear for Me
E.g. you have <ui:include src="#{bean.value}", where bean is view scope bean.
It is possible to still use dynamic page loading. You can use either of these 2 solutions:
Set javax.faces.PARTIAL_STATE_SAVING to false in web.xml for you project. It will trigger the jsf1.2 way of state saving.
When <ui:include/> evaluates the value - new instance of view scope bean is created and not taken from context. As a result, the default value for src taken. If you put the bean within the session scope (which is not good) or create new session scope bean which will contain only your page path string (to minimize session size), it will resolve the issue.
Here's another tip if you want to reset this session bean value from navigation from page to page. One of the ways is to create fake method "reset()" and put <c:if test="#{bean.reset}"></if> before <ui:include/> to make this initialization for your page. Reset can look like:
private String lastViewId;
public boolean isReset() {
String viewId = FacesContext.getCurrentInstance().getViewRoot().getViewId();
if (!viewId.equals(lastViewId)) {
lastViewId = viewId;
//make any clean here
}
return false;
}

Resources