How to execute single input validation by #FacesValidator using ajax event and render message? - ajax

usage:JSF 2.3.2 Mojarra
while adding ajax to my jsf i met such a case:
cannnot refresh: h:message id="phoneNumber-msg" during fulfill the form
<h:messages id="validation-messages" styleClass="validation-messages"/>
<h:form>
<h:outputLabel for="phoneNumber">Phone number</h:outputLabel>
<h:inputText id="phoneNumber" value="#{bean.phoneNumber}">
<f:validator validatorId="validators.PhoneNumber"/>
<f:ajax event="blur" execute="#this" render="phoneNumber-msg"/>
</h:inputText>
<h:message id="phoneNumber-msg" for="phoneNumber"/>
[...]
<h:commandButton value="Submit" action="#{userDetails.submit}"/>
</h:form>
and validators.PhoneNumber is a #FacesValidator:
#FacesValidator("validators.PhoneNumber")
public class PhoneNumberValidator implements javax.faces.validator.Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException { ... }
}
ADDITIONALLY
The validation work properly(message from validators.PhoneNumber occured in both: id="validation-messages" and id="phoneNumber-msg") when refreshed by the "Submit" button that ends the form:
<h:commandButton value="Submit" action="#{userDetails.submit}"/>
</h:form>
If you think about different validation way -> at EmailAddress input I used my own class anotation (EmailAddressValidator implements ConstraintValidator) which validates by #ValidEmailAddress on the bean used in the form - it renders the email validation message properly, but here I would like to validate PhoneNumber in a different way.
Is it possible to render id="phoneNumber-msg" (that means proceeding validators.PhoneNumber during fulfill the form?

Related

Render a component only when validation success

In JSF 2.X, can I render a component only when the validation success?
In my application I have many fields that must be filled. These data can be imported from a WebService through a search key.
When the user enter a valid search key the system searches the other fields and render them with the new values. But when the user enter a nonexistent key (or any other validation error) the server generates a validation error but still renders the fields, thus losing any data that there were filled.
What I need is that the user can perform the query and that if the query does not return results, this does not affect any data that he has already entered.
Below is a code example. Thus, if the user has filled in the fields inside updateThisOnSuccess and just after making an attempt to query without success, the value that is filled in is not lost.
<h:inputText value="#{controller.searchWebService}" >
<f:ajax execute="#this" render="updateThisOnSuccess messages" />
</h:inputText>
<h:panelGroup id="updateThisOnSuccess">
<h:inputText value="#{controller.field}" />
<!-- other fields -->
</h:panelGroup>
Submit the field values to run the search also does not seem an option as this will cause need to validate the fields inside updateThisOnSuccess.
Note: I saw the answer given by #BalusC to a similar question, but this is different from what I'm wondering why, in that case, foo-holder is always rendered and foo is conditioning. It's not my case, since this approach would make the controls do not appear when the validation fails.
Try this
<h:panelGroup id="updateThisOnSuccess">
<ui:fragment rendered="#{not facesContext.validationFailed}">
<h:inputText value="#{controller.field}" />
<!-- other fields -->
</ui:fragment>
</h:panelGroup>
Plaase try this. The requirements are that you must implement model validations with Bean Validation and the search field must implement JSF validation if required.
If you write "123456" then data is returned, else nothing is returned and a message is printed.
The backing bean:
#Named
#ViewScoped
public class yourBean implements Serializable{
private static final long serialVersionUID = 1L;
#Size(min=2)
private String field01;
private String searchWebService;
public void saveF(){
System.out.println("save");
}
public void searchWebServiceF(){
Boolean successWS = ("123456").equals(this.searchWebService);
if(successWS){
this.setField01("WS data");
}else{
FacesContext.getCurrentInstance().
addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "WS fails", ""));
}
}
public String getSearchWebService() {
return searchWebService;
}
public void setSearchWebService(String searchWebService) {
this.searchWebService = searchWebService;
}
public String getField01() {
return field01;
}
public void setField01(String field01) {
this.field01 = field01;
}
}
In your page:
<h:form id="form01">
<h:messages id="message"/>
<h:inputText id="wsid" value="#{pruebasBorradorBean.searchWebService}">
<f:validateLength maximum="6"/>
<f:ajax execute="#form" render="#form" listener="#{pruebasBorradorBean.searchWebServiceF()}" />
</h:inputText>
<h:panelGroup id="thedata">
<h:inputText value="#{pruebasBorradorBean.field01}">
<f:validateBean disabled="#{param['javax.faces.source']!='form01:save'}"/>
</h:inputText>
<!-- other fields -->
</h:panelGroup>
<h:commandButton id="save" value="submit">
<f:ajax render="thedata message" execute="#this thedata" listener="#{pruebasBorradorBean.saveF()}"/>
</h:commandButton>
</h:form>
You can change the components that will be processed in render phase changing the Collection at getRenderIds() of PartialViewContext. According to documentation this Collection is mutable.
FacesContext.getCurrentInstance().getPartialViewContext().getRenderIds().remove("formName:updateThisOnSuccess");
To test this solution, I used this controller:
#Named
#ViewScoped
public class Controller implements Serializable {
private static final long serialVersionUID = 1L;
private final static List<String> LIST_VALID_WEB_SERVICE_SEARCHS =
Arrays.asList(new String[] {"foo", "bar"});
private String webServiceParameter;
private Integer field01;
public void searchWebService() {
if (LIST_VALID_WEB_SERVICE_SEARCHS.contains(getWebServiceParameter())) {
setField01(123);
} else {
FacesContext facesContext = FacesContext.getCurrentInstance();
facesContext.getPartialViewContext().getRenderIds().remove("formFields");
FacesMessage facesMessage = new FacesMessage("Search not found in WebService.");
facesMessage.setSeverity(FacesMessage.SEVERITY_ERROR);
facesContext.addMessage("formName:searchWebService", facesMessage);
}
}
public void submit() {
System.out.println("submitted");
}
// Getters and Setters
}
And used this view:
<h:form id="formSearch">
<h:inputText id="webServiceParameter" value="#{controller.webServiceParameter}">
<f:ajax execute="#this" render="formFields messages" listener="#{controller.searchWebService}" />
</h:inputText><br />
</h:form>
<h:form id="formFields">
<h:inputText id="field01" value="#{controller.field01}" required="true">
<f:validateLongRange minimum="2" maximum="345" />
</h:inputText><br />
<!-- other fields -->
<h:commandButton value="submit" action="#{controller.submit}">
<f:ajax render="#form messages" execute="#form" />
</h:commandButton>
</h:form>
<h:messages id="messages" />
You can do something like that:
<f:ajax execute="#this" render="#{controller.success} message"/>
where success is a String attribute that will be empty if the WS fails and will be "updateThisOnSuccess" if not .
Or you could get rid of the JSF validation mechanism for informing the user the WS has failed. Think of it, it is not really a validation of the Model. You could draw an icon beside the WS Id field in red color or something similar using a boolean flag attribute in the backing bean.

Validate a number value without custom validator in JSF

I have a JSF form. I want a message to be displayed, when a user entered 0 in qty field and clicked on the Add To Card button.
Here is the JSF form:
<h:form>
<h:inputText id="qtyField" value="#{booksBean.qty}">
<!--What kind of validation should i use here?-->
<f:ajax event="blur" render="qtyMsg"/>
</h:inputText>
<h:message id="qtyMsg" for="qtyField"/>
<h:commandButton value="Add To Card"
action="#{booksBean.orderBook()}"
rendered="#{booksBean.qty>0}">
<f:ajax execute="#form" rendered="#form"/>
</h:commandButton>
</h:form>
Do I need a custom validator class just to simply compare a number value with a zero?
Like this:
#FacesValidator("myValidator")
public class MyValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value) {
if (intValue== 0 || intValue <0) {
throw new ValidatorException(new FacesMessage(...));
}
//...
}
Is there any shorter way without creating a custom validator class?
You can use f:validateLongRange for this.
<h:inputText value="#{backingBean.input1}">
<f:validateLongRange minimum="1" />
</h:inputText>
Checks whether the local value of a component is within a certain
range. The value must be any numeric type or String that can be
converted to a long.

How can I highlight UIInput using Primefaces when validation upon ajax request fails?

Validator Class:
#FacesValidator("br.gov.valec.sicpd.util.CpfValidator")
public class CpfValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value)
throws ValidatorException {
if (validateCpf(value.toString())) {
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR,"Invalid Input","Invalid Input");
((UIInput) component).setValid(false); // this line doesnt work
throw new ValidatorException(msg);
}
}
JSF snippet:
<p:inputText label="CPF" id="inputCpf"
value="#{mainBean.owner.cpf}">
<f:validator validatorId="br.gov.valec.sicpd.util.CpfValidator" />
<p:ajax event="change" update="inputNameOwner"
listener="#{mainBean.searchOwner}" />
</p:inputText>
When the form is submitted via command button primefaces highlights it automatically. How can I achieve that when ajax is fired and validation fails?
The UIInput#setValid(false) is working fine. You just forgot to tell ajax to update the input component itself. Add inputCpf or #this to <p:ajax update>.
<p:ajax ... update="#this inputNameOwner" />
That explicit UIInput#setValid(false) call in validator is by the way unnecessary. Get rid of it. JSF already does it all by itself once it catches the ValidatorException thrown by your validator.

Change InputText-Values with Ajax

So I have a bunch of InputText-Boxes, which express some kind of customer data (customer-id, firstname, lastname, etc.)
Now i want to auto-fill (with the corresponding mysql data) all InputText-Boxes, when I enter a valid customer-id.
<h:inputText id = "customer_id" value="#{reservationHandler.customer.customer_id}"/>
I guess I'll have to use Ajax to pass the current customer-id to the managed bean, but how do i do this? And how do i fill the other InputText-Boxes?
Thanks in advance.
This task can be done using the <f:ajax> tag that comes with JSF 2 and is good illustrated in this tutorial. The first example shows you how to accomplish the task at hand. Another advice would be to use #ViewScoped annotation for your managed bean as explained by BalusC blog post: Communication in JSF 2.0 - Managed bean scopes.
With all this info and the managed bean you're using, a demo could be:
Customer class
public class Customer {
private int customer_id;
private String name;
//constructor, getters and setters...
}
ReservationHandler managed bean
#ManagedBean
#ViewScoped
public class ReservationHandler {
private Customer customer;
//this EJB will retrieve the Customer data
//if you don't have it like this, then use your own
//custom CustomerService class/implementation to retrieve the data from dabatase
#EJB
private CustomerService customerService;
//constructor, getters and setters...
#PostConstruct
public void init() {
customer = new Customer();
}
public void showCustomerDataListener(AjaxBehaviorEvent event) {
Customer customerFromDB =
customerService.getCustomer(customer.getCustomer_id());
if (customerFromDB != null) {
customer = customerFromDB;
}
}
}
Customer Facelets view (just the relevant code)
<h:form>
<h:outputText value="Customer ID:" />
<h:inputText id="customer_id"
value="#{reservationHandler.customer.customer_id}">
<f:ajax event="blur"
listener="#{reservationHandler.showCustomerDataListener}"
render="customer_name" />
</h:inputText>
<h:outputText value="Customer name:" />
<h:inputText id="customer_name"
value="#{reservationHandler.customer.name}" />
</h:form>
In case your Customer class posses more than 1 attribute, you have two options:
Set the ID of every input in the render attribute of the <f:ajax> component, but this is very naive.
Group all the components with an UIContainer and render this UIContainer. Example given assuming that the Customer class has an additional private String address attribute:
<h:form>
<h:outputText value="Customer ID:" />
<h:inputText id="customer_id"
value="#{reservationHandler.customer.customer_id}">
<f:ajax event="blur"
listener="#{reservationHandler.showCustomerDataListener}"
render="customerData" />
</h:inputText>
<h:panelGrid id="customerData" columns="2">
<h:outputText value="Customer name:" />
<h:inputText id="customer_name"
value="#{reservationHandler.customer.name}" />
<h:outputText value="Address:" />
<h:inputText id="customer_address"
value="#{reservationHandler.customer.address}" />
</h:panelGrid>
</h:form>
To know the supported events that cna be applied in <f:ajax event="what_to_write_here">, refer to f:ajax JSF Core Tag Reference, event tag attribute description:
The event that will invoke Ajax requests, for example "click", "change", "blur", "keypress", etc. The event must be supported by the component(s) that have Ajax behavior enabled. Note: the event name is the same as the DOM event name without the "on" prefix, so for the "onclick" event the correct event name is "click". The "action" event is supported for command components such as h:commandButton and h:commandLink, and the "valueChange" event is supported for input components such as h:inputText and h:selectOneMenu.

How to know which component triggerd an p:ajax request

I have multiple input field with a p:ajax with a listener. They all connect to the same listener. How can I know what component triggerd the listener?
<h:inputText id="postalCode" size="20" value="# businessPartner.primaryAddress.postalCode}"
<p:ajax event="change" listener="#{businessPartner.primaryAddress.retrievePostalCodeCity}" >
</p:ajax>
</h:inputText>
<h:inputText id="city" size="60" value="# businessPartner.primaryAddress.city}"
<p:ajax event="change" listener="#{businessPartner.primaryAddress.retrievePostalCodeCity}" >
</p:ajax>
</h:inputText>
public void retrievePostalCodeCity() throws MWSException {
int country = address.getCountryId();
String postalCode = address.getPostalCode();
String city = address.getCity();
}
I have this problem because I used to use a4j ajax, but I'm moving the project to fully primefaces and no longer richfaces. The listener to a4j has an AjaxBehaviorEvent event and there I could do event.getComponent().getId()
How can I do the same with prime ajax?
The AjaxBehaviorEvent is not specific to RichFaces. It's specific to JSF2 itself. So you can just keep using it in PrimeFaces.
public void retrievePostalCodeCity(AjaxBehaviorEvent event) {
UIComponent component = event.getComponent();
// ...
}
As an alternative, or for the case that it's really not possible elsewhere, you could always use the new JSF2 UIComponent#getCurrentComponent() method.
public void retrievePostalCodeCity() {
UIComponent component = UIComponent.getCurrentComponent(FacesContext.getCurrentInstance());
// ...
}
By the way, the very same construct should work just fine with JSF2's own <f:ajax>. I do not see any reason to use <p:ajax> here. It would however be the only way if you were actually using a PrimeFaces component such as <p:inputText>.
Unrelated to the concrete problem, the event="change" is the default already. You can just omit it.
It is almost same in primefaces:
<p:ajax event="change" listener="#{businessPartner.primaryAddress.retrievePostalCodeCity}" />
import javax.faces.event.AjaxBehaviorEvent;
.....
public void retrievePostalCodeCity(AjaxBehaviorEvent event) {
...
}
If you want to access via button component action/actionListener tag you can use ActionEvent and for any case make sure you set ajax="true":
<p:commandLink actionListener="#{businessPartner.primaryAddress.retrievePostalCodeCity}" ajax="true" />
import javax.faces.event.ActionEvent;
....
public void retrievePostalCodeCity(ActionEvent event) {
...
}

Resources