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

Junit - Test fails on French or German string assertion

In my previous post about building a regex to check a text without special characters but allow German and French . I met a problem that the unit test works fine on my machine using Eclipse, but it was fail when running on Jenkins' build job. Here is my test: @Test public void shouldAllowFrenchAndGermanCharacters(){ String source = "ÄäÖöÜüß áÁàÀâÂéÉèÈêÊîÎçÇ"; assertFalse(SpecialCharactersUtils.isExistSpecialCharater(source)); } Production code: public static boolean isExistNotAllowedCharacters(String source){ Pattern regex = Pattern.compile("^[a-zA-Z_0-9_ÄäÖöÜüß áÁàÀâÂéÉèÈêÊîÎçÇ]*$"); Matcher matcher = regex.matcher(source); return !matcher.matches(); } The result likes the following: Failed tests: SpecialCharactersUtilsTest.shouldAllowFrenchAndGermanCharacters:32 null A guy from stackoverflow.com says: "This is probably due to the default encoding used for your Java source files. The ö in the string literal in the J...

How to apply Lean - Kanban for your business

This is the topic of Scrum Breakfast meetup this time, speaker: Ms. Phuong Bui - Technical Project Manager of YOOSE Pte. Ltd. http://www.meetup.com/Scrum-Breakfast-Vietnam-Agile-and-Scrum-Meetup/events/230313727/ Lean comes from Lean manufacturing is a method that focuses on elimination of wastes. In other words, this is a set of principles for archiving the quality, speed and customer alignment. The first time I knew about the term "Lean" is  from the book Software Craftsmanship . Sandro recommends if we want to transform our pet projects into a real business, we should get familiar with Lean Startup concepts. In this talk, Ms. Phuong pointed out some major wastes includes information (ex: unclear requirements), processes (ex: waiting), physical environment and people. Knowing what the problems should be the best way to eliminate them. The difference between  Single item flow and Batch processing is the second main point; and it is the Lean's idea. Batch pr...

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...

My must-have apps for daily work

There is no doubt that cool apps can help us be more productive and enjoyable at work. For the time being, I really love the following apps which are used by me almost every day. 1. A personal Kanban In fact, a personal kanban is the most useful app for me. Why does it matter? It is not just a to-do list, but it keeps me motivated every day because it helps me be able to know what my "big picture" is. I usually set up my plans together with a path to reach them.  KanbanFlow  is my preferred tool. KanbanFlow 2. A terminal Needless to say, a terminal is a must-have app for every developer, especially the ones use macOS/Linux. Due to its importance, I love to decorate and enhance it to be super exciting with various tools such as  iTerm ,  oh-my- zsh , and  thefuck . ;) iTerm + oh-my-zsh 3. A documentation "ecosystem" As a developer, I can not remember all things that I have experimented a day. Moreover, a document is really useful for sharing an...

Performance of a Data Structure

Why data structures matter The fact is that programs are all about processing data. Data structures are referred to how data is organized which affects the time of executing a program. How to measure the performance of a data structure In order to measure "how fast"/efficiency/performance of a data structure, we measure the performance of its operations. There are four basic operations including reading , searching , insertion , and deletion . A pure time consuming is not used for the measuring because it is not reliable depending on the hardware that it is run on. But instead, we use the term time complexity which refers to how many steps an operation takes. An example of how a single rule can affect efficiency Let's compare two data structures: Array and Set (with N elements). 1. Array - Reading : 1 step (because the computer has the ability to jump to any particular index in the array) - Searching : N steps (the worst case with linear search) - Inserti...