title: Invalidate Primefaces's datatable row on row edition
body: <p>I'm developing a web-app with JSF 2.1 + Primefaces 5.1. I have a datatable with row edition and each row has 2 <code>inputText</code>, 2 <code>selectOneMenu</code> and 1 <code>selectBooleanCheckbox</code>. I want to perform some business logic validation when clicking the check icon: it will validate the values of the 2 <code>selectOneMenu</code>s. For that, I created a custom validator associated with the second <code>selectOneMenu</code> that validates both values:</p>
  
  <pre class="lang-html prettyprint-override"><code>&lt;p:dataTable id="users_table_id" var="user" value="#{usersBean.users}" rowKey="#{user.id}" paginator="true"
              paginatorTemplate="{CurrentPageReport}  {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
                 rowsPerPageTemplate="5,10,15" emptyMessage="#{msgs.no_records}" sortBy="#{user.id}" sortOrder="ascending" rows="15" editable="true"&gt;
              &lt;f:facet name="header"&gt;
                  #{msgs.users}               
              &lt;/f:facet&gt;
              &lt;p:ajax event="rowEdit" listener="#{usersBean.onRowEdit}" update=":users_form_id:growl"/&gt;
              &lt;p:ajax event="rowEditInit" listener="#{usersBean.onRowEditInit}" update=":users_form_id:growl"/&gt;
              &lt;p:ajax event="rowEditCancel" listener="#{usersBean.onRowEditCancel}" update=":users_form_id:growl"/&gt;
              &lt;p:column headerText="#{msgs.id}" sortBy="#{user.id}" styleClass="centered-column"&gt;
                  #{user.id}
              &lt;/p:column&gt;          
              &lt;p:column headerText="#{msgs.description}" sortBy="#{user.description}" styleClass="centered-column"&gt;
                  &lt;p:cellEditor&gt;
                      &lt;f:facet name="output"&gt;#{user.description}&lt;/f:facet&gt;
                      &lt;f:facet name="input"&gt;&lt;p:inputText value="#{user.description}" styleClass="editable-cell"/&gt;&lt;/f:facet&gt;
                  &lt;/p:cellEditor&gt;
              &lt;/p:column&gt;          
              &lt;p:column headerText="#{msgs.password}" sortBy="#{user.password}" styleClass="centered-column"&gt;
                  &lt;p:cellEditor&gt;
                      &lt;f:facet name="output"&gt;#{user.password}&lt;/f:facet&gt;
                      &lt;f:facet name="input"&gt;&lt;p:inputText value="#{user.password}" styleClass="editable-cell"/&gt;&lt;/f:facet&gt;
                  &lt;/p:cellEditor&gt;
              &lt;/p:column&gt;
              &lt;p:column headerText="#{msgs.sending_system}" sortBy="#{user.playerIn.description}" styleClass="centered-column"&gt;
                  &lt;p:cellEditor&gt;
                      &lt;f:facet name="output"&gt;#{user.playerIn.description}&lt;/f:facet&gt;
                      &lt;f:facet name="input"&gt;
                          &lt;p:selectOneMenu binding="#{userPlayerInComponent}" styleClass="editable-cell" id="users_table_sending_system_id" value="#{user.playerIn}" effectSpeed="fast" filter="true" filterMatchMode="contains" converter="#{playerConverter}"&gt;
                              &lt;f:selectItem itemLabel="#{msgs.select_option}" itemValue="#{null}" noSelectionOption="true"/&gt;
                              &lt;f:selectItems value="#{usersBean.players}" var="player" itemValue="#{player}" itemLabel="#{player.description}"/&gt;
                          &lt;/p:selectOneMenu&gt;
                      &lt;/f:facet&gt;
                  &lt;/p:cellEditor&gt;
              &lt;/p:column&gt; 
              &lt;p:column headerText="#{msgs.receiving_system}" sortBy="#{user.playerOut.description}" styleClass="centered-column"&gt;
                  &lt;p:cellEditor&gt;
                      &lt;f:facet name="output"&gt;#{user.playerOut.description}&lt;/f:facet&gt;
                      &lt;f:facet name="input"&gt;
                          &lt;p:selectOneMenu styleClass="editable-cell" id="users_table_receiving_system_id" value="#{user.playerOut}" effectSpeed="fast" filter="true" filterMatchMode="contains" converter="#{playerConverter}"&gt;
                              &lt;f:selectItem itemLabel="#{msgs.select_option}" itemValue="#{null}" noSelectionOption="true"/&gt;
                              &lt;f:selectItems value="#{usersBean.players}" var="player" itemValue="#{player}" itemLabel="#{player.description}"/&gt;
  
                              &lt;f:validator validatorId="userValidator"/&gt;
                              &lt;f:attribute name="userPlayerInComponent" value="#{userPlayerInComponent}"/&gt;
                          &lt;/p:selectOneMenu&gt;
                      &lt;/f:facet&gt;
                  &lt;/p:cellEditor&gt;
              &lt;/p:column&gt;                                     
              &lt;p:column headerText="#{msgs.active}" sortBy="#{user.active}" styleClass="centered-column"&gt;
                  &lt;p:cellEditor&gt;
                      &lt;f:facet name="output"&gt;&lt;p:selectBooleanCheckbox value="#{user.active}" disabled="true"/&gt;&lt;/f:facet&gt;              
                      &lt;f:facet name="input"&gt;&lt;p:selectBooleanCheckbox value="#{user.active}"/&gt;&lt;/f:facet&gt;
                  &lt;/p:cellEditor&gt;
              &lt;/p:column&gt;
              &lt;p:column styleClass="datatable-row-editor"&gt;
                  &lt;p:rowEditor/&gt;
              &lt;/p:column&gt;
              &lt;f:facet name="footer"&gt;
              &lt;/f:facet&gt;      
          &lt;/p:dataTable&gt;
  </code></pre>
  
  <pre class="lang-java prettyprint-override"><code>@FacesValidator("userValidator")
  public class UserValidator implements Validator {
  
      private static final Logger logger =  LogManager.getLogger(UserValidator.class);
  
      @Override
      public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
          logger.entry(context, component, value);
  
          if (value == null) {
              return; // Let required="true" handle.
          }
  
          UIInput userPlayerInComponent = (UIInput)component.getAttributes().get("userPlayerInComponent");
          if (!userPlayerInComponent.isValid()) {
              return; // Already invalidated. Don't care about it then.
          }
  
          DtoPlayer playerIn = (DtoPlayer)userPlayerInComponent.getValue();
          if (playerIn == null) {
              return; // Let required="true" handle.
          }
  
          DtoPlayer playerOut = (DtoPlayer)value;
  
          UsersBean usersBean = context.getApplication().evaluateExpressionGet(context, "#{usersBean}", UsersBean.class);
  
          BigDecimal userId = usersBean.getUserEditingId();
          logger.info(userId + " - " + playerIn.getDescription() + " - " + playerOut.getDescription());
  
          for (DtoUser dtoUser : usersBean.getUsers()) {
              if (!userId.equals(dtoUser.getId()) &amp;&amp; dtoUser.getPlayerIn().equals(playerIn) &amp;&amp; dtoUser.getPlayerOut().equals(playerOut)) {
                  logger.info("Invalidating...");
                  userPlayerInComponent.setValid(false);              
                  FacesContext.getCurrentInstance().validationFailed();
                  throw new ValidatorException(new FacesMessage("BOOM!"));
              }
          }
          logger.exit();
      }
  }
  </code></pre>
  
  <p>I was expecting that, when validation fails (and a <code>ValidatorException</code> is thrown), the datatable row would stay in edit mode and the two <code>selectOneMenu</code>s highlighted with red colour. But what happens is that the row exits from edit mode, keeping the old values. If I edit it again, it displays the submitted values and the invalid cells are marked with red. And this behaviour continues as long as I try to submit the invalid values. If I close the edit mode, the invalid values are discarded and the row keeps only the old values (whether in view or edit mode).</p>
  
  <p>How can I solve this? From the <a href="http://www.primefaces.org/showcase/ui/data/datatable/edit.xhtml" rel="nofollow">Primefaces' showcase</a>, one can see that when you try to submit, let's say, a string with alfabetic characters in the year cell, the row keeps the edit mode and is highlighted. I want to achieve the same behaviour.</p>