Skip to main content

JSF, Primefaces - Invoking Application Code Even When Validation Failed


A use case

I have a form which has requirements as follow:
- There are some mandatory fields.
- Validation is triggered when changing value on each field.
- A button "Next" is enable only when all fields are entered. It turns to disabled if any field is empty.

My first approach

I defined a variable "isDisableNext" at a backend bean "Controller" for dynamically disabling/enabling the "Next" button by performing event "onValueChange", but, it had a problem:
<h:form id="personForm">
   <p:outputLabel value="First Name" for="firstName"/>
   <p:inputText id="firstName" value="#{person.firstName}"
     required="true">
    <p:ajax event="change" listener="#{controller.onValueChange}" update="nextButton"/>
   </p:inputText>
   
   <p:outputLabel value="Last Name" for="lastName"/>
   <p:inputText id="lastName" value="#{person.lastName}"
     required="true">
    <p:ajax event="change" listener="#{controller.onValueChange}" update="nextButton"/>
   </p:inputText>
   
   <p:commandButton id="nextButton" actionListener="#{controller.onNext}" update="personForm" disabled="#{controller.isDisabledNext}"/>
</h:form>
Due to JSF lifecyle, the application code of Ajax "onValueChange" (at phase Invoke Application) is never invoked when validation failed. How could we update the value "isDisableNext"?
src: http://docs.oracle.com/javaee/5/tutorial/doc/bnaqq.html

My new approach: I don't try to update the backend bean at phase Invoke Application anymore but use custom validator

What is it? And, why is it possible?
- At phase Process Validation, it always calls my application code even when validation failed
- I handle enabling/disabling the button with JSF component tree instead of a backend bean.

The previous implementation turns to the following:
- Don't use required="true" because it won't invoke customer validators when a field's submitted value is empty. Then I need to add the "*" manually with "span class="ui-outputlabel-rfi".
- Use custom validator with "f:validator"
- Pass component button "Next" with "f:attribute" and "binding"
<h:form id="personForm">
   <p:outputLabel value="First Name" for="firstName">
    <span class="ui-outputlabel-rfi">*</span>
   </p:outputLabel>
   <p:inputText id="firstName" value="#{person.firstName}">
    <p:ajax event="change" listener="#{controller.onValueChange}" update="nextButton"/>
    <f:validator validatorId="requiredFieldValidator"/>
    <f:attribute name="nextButton" value="#{nextButton}"/>
   </p:inputText>
   
   <p:outputLabel value="Last Name" for="lastName">
    <span class="ui-outputlabel-rfi">*</span>
   </p:outputLabel>
   <p:inputText id="lastName" value="#{person.lastName}">
    <p:ajax event="change" listener="#{controller.onValueChange}" update="nextButton"/>
    <f:validator validatorId="requiredFieldValidator"/>
    <f:attribute name="nextButton" value="#{nextButton}"/>
   </p:inputText>
   
   <p:commandButton id="nextButton" actionListener="#{controller.onNext}" update="personForm" binding="#{nextButton}"/>
</h:form>
The custom validator looks like:
@FacesValidator(value = "requiredFieldValidator")
public class RequiredFieldValidator implements Validator{

 public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
  CommandButton nextButtonUi = (CommandButton) component.getAttributes().get("nextButton");
  Map<String, String> requestParameterMap = context.getExternalContext().getRequestParameterMap();
  String firstName = requestParameterMap.get(getClientId("firstName"));
  String lastName = requestParameterMap.get(getClientId("lastName"));
  if(StringUtils.isEmpty(firstName) || StringUtils.isEmpty(lastName)) {
   nextButtonUi.setDisabled(true);
  }else {
   nextButtonUi.setDisabled(false);
  }
  
  RequestContext.getCurrentInstance().update(getClientId("nextButton"));
 }

}
How is your approach? Leave your comment down below!

Comments

Popular posts from this blog

[Snippet] CSS - Child element overlap parent

I searched from somewhere and found that a lot of people says a basic concept for implementing this feature looks like below: HTML code: <div id="parent">  <div id="child">  </div> </div> And, CSS: #parent{   position: relative;   overflow:hidden; } #child{   position: absolute;   top: -1;   right: -1px; } However, I had a lot of grand-parents in my case and the above code didn't work. Therefore, I needed an alternative. I presumed that my app uses Boostrap and AngularJs, maybe some CSS from them affects mine. I didn't know exactly the problem, but I believed when all CSS is loaded into my browser, I could completely handle it. www.tom-collinson.com I tried to create an example to investigated this problem by Fiddle . Accidentally, I just changed: position: parent; to position: static; for one of parents -> the problem is solved. Look at my code: <div class="modal-body dn-placeholder-parent-positi...

Automating deployment and managing apps on OpenShift

Previously, we maintained OpenShift templates for deploying apps in development environments as well as delivering these templates to our customers for their on-prem deployment. Customers who refer to our templates (as well as documentation) have their own configuration management tools to automate the deployment such as ArgoCD and FluxCD. My son's buildings Our developers usually modify templates (YAML) directly on OpenShift for testing and then adjust the corresponding templates stored in the Git repository in Bitbucket. This sometimes causes an issue that delivered templates are incorrect because: - Developers forget to update the templates in Git repositories. - Developers don’t test the templates Therefore, our goal was to integrate a tool into our CI/CD that can automate and manage the configuration of OpenShift apps. The delivered templates should be the ones that are able to run on our OpenShift with the following purposes: - Automate deployment from templated in Git repos...

Coding Exercise, Episode 1

I have received the following exercise from an interviewer, he didn't give the name of the problem. Honestly, I have no idea how to solve this problem even I have tried to read it three times before. Since I used to be a person who always tells myself "I am not the one good at algorithms", but giving up something too soon which I feel that I didn't spend enough effort to overcome is not my way. Then, I have sticked on it for 24 hours. According to the given image on the problem, I tried to get more clues by searching. Thanks to Google, I found a similar problem on Hackerrank (attached link below). My target here was trying my best to just understand the problem and was trying to solve it accordingly by the Editorial on Hackerrank. Due to this circumstance, it turns me to love solving algorithms from now on (laugh). Check it out! Problem You are given a very organized square of size N (1-based index) and a list of S commands The i th command will follow t...

Java 8 - Persistent data structure

The following is a series of posts about "functional programming in Java" which is the result of my understanding by reading the book " Java 8 in Action: Lambdas, Streams, and Functional-style Programming, by Alan Mycroft and Mario Fusco ". 1. Why functional programming? 2. Functional programming in Java 8 3. Java 8 - Using Functions as Values 4. Java 8 - Persistent data structure Persistent data structure is also known as a simple technique but it's very important. Its other names are functional data structure and immutable data structure. Why is it "persistent"? Their values persist and are isolated from changes happening elsewhere. That's it! This technique is described as below: If you need a data structure to represent the result of a computation, you should make a new one and not mutable an existing data structure. Destructive updates version public static A doSomething(A a){ a.setProp1("new value"); return...

Generating PDF/A From HTML in Meteor

My live-chat app was a folk of project Rocket.Chat which was built with Meteor. The app had a feature that administrative users were able to export the conversations into PDF files. And, they wanted to archive these files for a long time. I happened to know that PDF/A documents were good for this purpose. It was really frustrated to find a solution with free libraries. Actually, it took me more than two weeks to find a possible approach. TL, DR; Using Puppeteer to generate a normal PDF and using PDFBox to load and converting the generated PDF into PDF/A compliance. What is PDF/A? Here is a definition from Wikipedia: PDF/A  is an  ISO -standardized version of the  Portable Document Format  (PDF) specialized for use in the  archiving  and long-term  preservation  of  electronic documents . PDF/A differs from PDF by prohibiting features unsuitable for long-term archiving, such as  font  linking (as opposed to  font em...