Search code examples
jsfjsf-2richfaces

Validate rich:dataTable value size's on form submit


I have a "new item" form that requires a list of dates, with the following components:

  • A <rich:calendar> input;
  • A <a4j:commandButton> that adds the chosen date to a List<Date> chosenDates in the backing bean;
  • A <rich:dataTable> with it's value set to the List<Date> chosenDates attribute;
  • A <a4j:commandButton> per dataTable row that removes it's date from theList<Date> chosenDates;

How to validate (JSF's validation phase) the size of the chosenDates list on form submit (creation process)?

RichFaces 4, JSF 2.1 (Mojarra).


Solution

  • I'd advise a cleaner approach with a JSF PhaseListener. The JSF processing will stop skip ahead the other phases if validation fails. Create a PhaseListener that will inspect the size of your list during the validations phase as against during the model update/invoke action phase. Try something like this

    1. Create a phase listener for the validations phase

      public class TestPhaseListener implements PhaseListener {
      
         @Override
         public void afterPhase(PhaseEvent event) {
            throw new UnsupportedOperationException("Not supported yet.");
         }
      
         @Override
         public void beforePhase(PhaseEvent event) {
      
            if(event.getPhaseId().equals(PhaseId.PROCESS_VALIDATIONS)){
              FacesContext ctx = event.getFacesContext();
              YourBeanClass theBeanClass = ctx.getApplication().evaluateExpressionGet(ctx, "#{someBean}", YourNeanClass.class); //obtain a reference to the backing bean containing the list
      /*
         inspect the size of the list here and based on that throw the exception below
       */
             throw new ValidatorException(new FacesMessage("Too many dates","Too Many Dates"));
            }
         }
      
          @Override
          public PhaseId getPhaseId() {
             throw new UnsupportedOperationException("Not supported yet.");
          }
       } 
      
    2. Register your new listener in the faces_config.xml file

      <lifecycle>
         <phase-listener>your.package.structure.TestPhaseListener</phase-listener>
      </lifecycle>
      

    EDIT: Based on your comment, as an alternative, you can hook into the component's lifecycle using the <f:event/> tag and the preValidate or postValidate events (depending on your preference)

    1. A listener tag to your component

         <rich:dataTable>
             <f:event type="preValidate" listener="#{yourBean.listener}"/>
         </rich:dataTable>
      
    2. Define a listener method in your backing bean to run per your defined event. The method signature must take an argument of type ComponentSystemEvent

          public void preCheck(ComponentSystemEvent evt){
             //You're in your backing bean so you can do pretty much whatever you want. I'd advise you mark the request as validation failed and queue FacesMessages. Obtain a reference to FacesContext and:
      
              facesContext.validationFailed();
      
      
           }