How to migrate JSF Validator to Bean Validation? - jsf-2

The usual way to perform JSF validation in an imperative manner is to add validator tag to JSF and have a corresponding Validator class like the following :
View:
<h:outputLabel for="email" value="*Enter Email: " title="Primary Email"/>
<h:inputText id="email" value="#{personView.per.email}" required="true" requiredMessage="email is required"
title="Primary Email" tabindex="3">
<f:validator validatorId="emailValidator" />
</h:inputText>
<h:message id="m2a" for="email" style="color:red"/> <p></p>
Validator:
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
log("Validating submitted email -- " + value.toString());
matcher = pattern.matcher(value.toString());
if (!matcher.matches()) {
FacesMessage msg =
new FacesMessage(" E-mail validation failed.",
"Please provide E-mail address in this format: abcd#abc.com");
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(msg);
}
}
Now here the validation is getting triggered by the JSF. I want to change that part and want that the validation is instead triggered from another Controller via a Bean Validation constraint. That means that, I want to remove the following part :-
<f:validator validatorId="emailValidator" />
and want that this validation is triggered from another controller via a Bean Validation constraint.
Note that, I cannot add the constraint directly on the entity as the entity is a generated file. I want do the validation in the controller itself such that incase of error I could show the error message on the UI.
How can I go about it?
Explanation with some sample code would be appreciated.

Related

Add Validation Message To View

Lets say I have a form with no model binding or data annotations. When the form is posted how can I return the view with a validation message beneath the control - Note I'm trying to do server side validation here?
Below is a kind of example.
<input name="Address" type="text" value="">
<span class="field-validation-valid" data-valmsg-for="Address" data-valmsg-replace="true"></span>
public ActionResult Create(FormCollection collection)
{
if (string.IsNullOrEmpty(collection["Address"])
{
// Set the field validation error span message
ModelState.AddModelError("Address", "This field is required.");
return View();
}
}
Note: I know how add validation using a view model and data annotations. In this scenario I'm unable to use a view model so need some way to manually validate and return the validation messages back to the view.
The above doesn't seem to work
* Update *
Perhaps using viewData as follows:
<span class="field-validation-valid" data-valmsg-for="Address" data-valmsg-replace="true">#ViewData["Address"]</span>
I would go with html helpers.
#Html.ValidationMessage("Address")
This will automatically generate the HTML:
<span class="field-validation-valid" data-valmsg-for="address" data-valmsg-replace="true"></span>`
Your code looks correct.
if (string.IsNullOrEmpty(collection["Address"]))
{
// Set the field validation error span message
ModelState.AddModelError("Address", "This field is required.");
return View();
}

jsf changing class of an element

I want to change a div's class dynamically based on if an input value is true or false. Thought the function that validates the input is called the class is never changed. Here's the xhmtl:
<td>
<div class="#{regBean.nameclass}">
<h:inputText class="form-control input-sm" value="#{regBean.name}">
<f:ajax event="blur" listener="#{regBean.validateName}" render="namemsg" />
</h:inputText>
</div>
</td>
<td class="error">
<h:outputText class="error-msg" id="namemsg" value="#{regBean.nameMsg}"></h:outputText>
</td>
and here's the function from the according bean:
private static final String SUCCESS="form-group has-success";
private static final String ERROR="form-group has-error";
public void validateName(){
if(ValidatorUtilities.empty(name)){
nameMsg="Παρακαλώ εισάγετε όνομα!";
}
nameMsg=ValidatorUtilities.validateName(name);
if(nameMsg.equals("")){
nameclass=SUCCESS;
validations.put("name",true);
}
else{
nameclass=ERROR;
validations.put("name",false);
}
}
thought the message at element with id="namemsg" is correctly shown the class remains the same. Is there anything wrong or am I going for the wrong implementation and should do this client side by jquery?
Note:I've set the getter-setter for the string nameclass
Your code is not re-rendering the <div>. Your code is only re-rendering the <h:outputText>. I'm not sure why and how exactly you expected that the <div> is also covered by the re-rendering. All you need to so is to specify its client ID in the render attribute as well. You only need to replace <div> by <h:panelGroup layout="block">, because rendering can only target true JSF components.
<td>
<h:panelGroup id="field" layout="block" styleClass="#{regBean.nameclass}">
<h:inputText ...>
<f:ajax ... render="field namemsg" />
</h:inputText>
</h:panelGroup>
</td>
<td class="error">
<h:outputText id="namemsg" ... />
</td>
Unrelated to the concrete problem, your whole validation approach is utterly broken. You're supposed to use a true Validator and a <h:message>, exactly like as shown in every decent JSF book. This is also a strong hint that you still don't have one. I warmly recommend to work on that first.
See also:
How to create JSF form with AJAX data validation
How to perform validation in JSF, how to create a custom validator in JSF

struts2 with 3 dependent dropdowns without using ajax

I'm using Struts 2 and MySQL.
In my JSP I have 3 select controls:
<s:select list="country" name="country" onchange="getstate();" />
<s:select list="state" name="state" onchange="getcity();" />
<s:select list="city" name="city" />
In my action class:
public string displayDetails() {
getCountry();
getState(getCountry());
getCity(getState());
}
If I want to get state I have to access getCountry() method again. How can I avoid that call every time?
If I'm not adding all the action in one method I'm getting "list field is not filled" error.

Can't we link a grails form to a bean

As in Struts n JSF, we link a form to a bean(eg. backing bean in JSF).
But in grails, we are using params to set values of the bean. Is there any other way to automatically map a form to the bean?
Grails has the possibility to auto bind values from the params map to a given domain instance / command object. This can be achieved by defining the correct beans as a parameter for your controller methods. Take this example:
Controller:
class AuthorController {
def save(Author author) {
// matching param values are bound to the author instance
assert params.name == "myName"
assert author.name == "myName"
}
}
gsp with form:
<g:form controller="author" action="save">
<g:field name="name" value="myName" />
<g:submitButton name="save" value="Save" />
</g:form>
Sometimes is better to use the Command Objects provided by Grails, the domain class can be wrapped only matching the name of the form fields with the attributes names of the class.
But Command Objects can provide an intermediate layer of validation and abstraction to generate the model bean.
http://grails.org/doc/2.3.0/guide/single.html#commandObjects

primefaces autocomplete when cleared field giving previuos results of page on clicking submit button

I am using an autocomplete tag of prime faces which retrieves results from a database.
The problem is that when I submit the form leaving the autocomplete field empty the results I get on the page are those of the previous request (the previously selected autocomplete value) - it only gets cleared when I refresh the page.
I want that on each submit, without refreshing the browser page, if i clear out the value in the field using backspaces and submit the form it should give the correct result for this particular instance, not previous one.
I am also using some textfields in the jsf page form but those don't have this problem.
Can anyone offer guidance as to how this problem can be corrected?
EDITED:
Code:
<h:form>
<h:dataTable id="Ressult" value="#{input.searchResults}" var="r">
<h:column>#{r.ID}</h:column>
<h:column>#{r.Name}</h:column>
</h:dataTable>
<tr>
<td>Current Education Level</td>
<td>
<h:panelGrid styleClass="text-box">
<p:autoComplete id="education" value="#{input.education}"
completeMethod="#{input.getautocomplete}" var="a"
itemLabel="#{a.Name}" itemValue="#{a}"
converter="edConverter" forceSelection="true" />
<p:column>#{a.Name} - #{a.id}</p:column>
</h:panelGrid>
</td>
</tr>
<tr>
<td>City</td>
<td>
<h:selectOneMenu id="txtCity" styleClass="select-field"
value="#{input.cityId}">
<f:selectItem itemLabel=" Please Select" itemValue="0">
</f:selectItem>
<f:selectItems value="#{input.cities}"></f:selectItems>
</h:selectOneMenu>
</td>
</tr>
<tr>
<td>Name of Person</td>
<td>
<h:inputText id="txtName" value="#{input.nameOfPerson}"
styleClass="text-box"></h:inputText>
</td>
</tr>
<h:commandButton id="btnSearch" value="Search"
action="#{input.searching}">
<f:ajax execute="#form" render="Ressult"></f:ajax>
</h:commandButton>
</h:form>
And here is the bean code:
public class Input
{
private Education education;
private List<SelectItem> cities;
private Integer cityId;
private String nameOfPerson;
private List<Results> searchResults;
//getters and setters
public String searching()
{
searchResults=dao.getSearchResults(cityId,education,nameOfPerson);
return "success";
}
public void autocomplete(String query)
{
//AUTOCOMPLTE lIST CODE HERE
}
}
By update, if you mean new results to be shown when new items selected, then yes - the form should be updated but autocomplete somehow takes the previously selected value and shows results according to that. At least until I refresh the page - only then is autocomplete's previous is removed.
I had the same problem with my autocomplete widget.
When I removed its id attribute it worked. Maybe a bug in Primefaces.
You may have two things to do:
Prevent the user from submission by pressing the Enter key by doing the following in your form:
<h:form onkeypress="return event.keyCode != 13;">
Using itemSelect/itemUnselect features provided to empty the field in the Bean:
<p:ajax event="itemSelect"
listener="#{autoCompleteBean.handleSelect}" global="false"
update=":some:where" />
<p:ajax event="itemUnselect"
listener="#{autoCompleteBean.handleUnselect}" global="false"
update=":some:where" />
<!-- rest of your facelet stuff -->
In the Bean:
public void handleSelect(final SelectEvent event) {
final Search search = (Search) event.getObject();
// do your addition here
}
public void handleUnselect(final UnselectEvent event) {
final Search search = (Search) event.getObject();
// do your substraction here
}
Well if i understand your question correctly your list of auto completion is shown after the post. And you use your form to submit time after time to the same page.
Your bean looks a little bit odd. Because you're calling in the page the autocomplete method: getautocomplete but that one doesn't exists in your bean.
Use the autocomplete in this way:
<p:autoComplete id="education" value="#{input.education}" completeMethod="#{input.autocomplete}" var="a" itemLabel="#{a.Name}" itemValue="#{a}" converter="edConverter" forceSelection="true" />
And in your bean:
public List<Education> autocomplete(String query)
{
List<Education> educations = new ArrayList<Education>();
//search with query in your dao something like:
educations = dao.searchEducation(query);
return educations;
}
fixed on 5.2, upgrade your primefaces jar
here the log issue
https://code.google.com/p/primefaces/issues/detail?id=7592
To fix the subject issue you just remove the forceselection
or make it as false.
Just process event to server. Works with forceselection="true"
<p:ajax event="itemUnselect" global="false" />

Resources