RueKow
RueKow

Reputation: 203

PrimeFaces datatable - is cross-validation possible?

I have a datatable with input fields. On form submit I must validate all inputs together. Validating is no problem, however putting ui-state-error on invalid fields makes trouble. I tried to determine component with UIViewRoot#findComponent(id), but this method always returns NULL. I got "id" from firebug, so I do not understand what is going wrong???

I hope that anyone can help me!

My datatable:

                       <prime:dataTable id="dtSpielberichtErfassen2"
                          value="#{bsvttController.spielDetailListe}" var="dtSpiErf2"
                          selection="#{bsvttController.selectedSpielDetail}" selectionMode="single"
                          rowKey="#{dtSpiErf2.id}">

                          <prime:column style="width:55px">
                             <h:outputText value="#{dtSpiErf2.spielPaarung}" />
                          </prime:column>

                          <prime:column style="width:180px"
                             headerText="#{bsvttController.mannschaftHeim}">
                             <h:panelGrid id="pgSpiErf1"
                                columns="1" cellpadding="0" cellspacing="0"
                                styleClass="#{dtSpiErf2.saetzeGewonnen == 3 ? 'fett' : null}">
                                <h:outputText value="#{dtSpiErf2.posHeim1}" />
                                <h:outputText value="#{dtSpiErf2.posHeim2}" />
                             </h:panelGrid>
                          </prime:column>

                          <prime:column style="width:180px"
                             headerText="#{bsvttController.mannschaftGast}">
                             <h:panelGrid id="pgSpiErf2"
                                columns="1" cellpadding="0" cellspacing="0"
                                styleClass="#{dtSpiErf2.saetzeVerloren == 3 ? 'fett' : null}">
                                <h:outputText value="#{dtSpiErf2.posGast1}" />
                                <h:outputText value="#{dtSpiErf2.posGast2}" />
                             </h:panelGrid>
                          </prime:column>

                          <prime:column style="width:50px"
                             headerText="1. Satz">
                             <h:panelGrid columns="3" cellpadding="0" cellspacing="0">
                                <pe:inputNumber id="inG1" value="#{dtSpiErf2.satz1Gewonnen}"
                                   maxlength="2" decimalPlaces="0"
                                   style="width:20px; text-align:right">
                                </pe:inputNumber>
                                <h:outputText value=":" />
                                <pe:inputNumber id="inV1" value="#{dtSpiErf2.satz1Verloren}"
                                   maxlength="2" decimalPlaces="0"
                                   style="width:20px; text-align:left">
                                </pe:inputNumber>
                             </h:panelGrid>
                          </prime:column>

                          <prime:column style="width:50px"
                             headerText="2. Satz">
                             <h:panelGrid columns="3" cellpadding="0" cellspacing="0">
                                <pe:inputNumber id="inG2" value="#{dtSpiErf2.satz2Gewonnen}"
                                   maxlength="2" decimalPlaces="0"
                                   style="width:20px; text-align:right">
                                </pe:inputNumber>
                                <h:outputText value=":" />
                                <pe:inputNumber id="inV2" value="#{dtSpiErf2.satz2Verloren}"
                                   maxlength="2" decimalPlaces="0"
                                   style="width:20px; text-align:left">
                                </pe:inputNumber>
                             </h:panelGrid>
                          </prime:column>

                          <prime:column style="width:50px"
                             headerText="3. Satz">
                             <h:panelGrid columns="3" cellpadding="0" cellspacing="0">
                                <pe:inputNumber id="inG3" value="#{dtSpiErf2.satz3Gewonnen}"
                                   maxlength="2" decimalPlaces="0"
                                   style="width:20px; text-align:right">
                                </pe:inputNumber>
                                <h:outputText value=":" />
                                <pe:inputNumber id="inV3" value="#{dtSpiErf2.satz3Verloren}"
                                   maxlength="2" decimalPlaces="0"
                                   style="width:20px; text-align:left">
                                </pe:inputNumber>
                             </h:panelGrid>
                          </prime:column>

                          <prime:column style="width:50px"
                             headerText="4. Satz">
                             <h:panelGrid columns="3" cellpadding="0" cellspacing="0">
                                <pe:inputNumber id="inG4" value="#{dtSpiErf2.satz4Gewonnen}"
                                   maxlength="2" decimalPlaces="0"
                                   disabled="#{bsvttController.disable2(dtSpiErf2, 4)}"
                                   style="width:20px; text-align:right">
                                </pe:inputNumber>
                                <h:outputText value=":" />
                                <pe:inputNumber id="inV4" value="#{dtSpiErf2.satz4Verloren}"
                                   maxlength="2" decimalPlaces="0"
                                   disabled="#{bsvttController.disable2(dtSpiErf2, 4)}"
                                   style="width:20px; text-align:left">
                                </pe:inputNumber>
                             </h:panelGrid>
                          </prime:column>

                          <prime:column style="width:50px"
                             headerText="5. Satz">
                             <h:panelGrid columns="3" cellpadding="0" cellspacing="0">
                                <pe:inputNumber id="inG5" value="#{dtSpiErf2.satz5Gewonnen}"
                                   maxlength="2" decimalPlaces="0"
                                   disabled="#{bsvttController.disable2(dtSpiErf2, 5)}"
                                   style="width:20px; text-align:right">
                                </pe:inputNumber>
                                <h:outputText value=":" />
                                <pe:inputNumber id="inV5" value="#{dtSpiErf2.satz5Verloren}"
                                   maxlength="2" decimalPlaces="0"
                                   disabled="#{bsvttController.disable2(dtSpiErf2, 5)}"
                                   style="width:20px; text-align:left">
                                </pe:inputNumber>
                             </h:panelGrid>
                          </prime:column>

                       </prime:dataTable>

Code snippet of my validation method:

        // %1% - index of datatable row
        // %2% - identifying part of componet id
        String id = ":formBsvtt:caseUpdateSpielberichtErfassen:dtSpielberichtErfassen2:%1%:in%2%_input";
        int saetzeGesamtGewonnen = 0;
        int saetzeGesamtVerloren = 0;
        int spieleGesamtGewonnen = 0;
        int spieleGesamtVerloren = 0;
        FacesContext fc;
        FacesMessage fm;
        UIComponent uic;
        UIInput uii;
        //
        // Prüfung 1: Sätze korrekt? -> 11:n oder n:11 oder n+2:n(ab n=10)
        for (int i = 0; i < spielDetailListe.size(); i++)
        {
           SpielDetail sd = spielDetailListe.get(i);
           if (!istSatzende(sd.getSatz1Gewonnen(), sd.getSatz1Verloren()))
           {
              fc = FacesContext.getCurrentInstance();
              fm = new FacesMessage(FacesMessage.SEVERITY_ERROR,
                    "Je Satz sind mindestens 11 Punkte und eine Diffenrenz von 2 Punkten notwendig.", "");
              fc.addMessage("", fm);
              id = id.replace("%1%", String.valueOf(i)).replace("%2%", "G1");
              uic = fc.getViewRoot().findComponent(id);
              if (uic != null)
              {
                 uii = (UIInput) uic;
                 uii.setValid(false);
              }
              return false;
           }
        }

Upvotes: 0

Views: 778

Answers (1)

kolossus
kolossus

Reputation: 20691

Your work will be cleaner and smoother if you implement a standalone validator and declare that validator on the input component within the datatable. What you're trying to do is unmaintainable and unecessarily binds the view to the model. I'd advise you

  1. Abstract your validation logic to a proper Validator. Below is just a dummy impl.

      @FacesValidator("myValidator")
      public class MyValidator implements Validator{
    
       public void validate(FacesContext context, UIComponent component,
        Object value) throws ValidatorException {
            for (int i = 0; i < spielDetailListe.size(); i++)
    {
       SpielDetail sd = spielDetailListe.get(i);
       if (!istSatzende(sd.getSatz1Gewonnen(), sd.getSatz1Verloren()))
       {
          fc = FacesContext.getCurrentInstance();
          fm = new FacesMessage(FacesMessage.SEVERITY_ERROR,
                "Je Satz sind mindestens 11 Punkte und eine Diffenrenz von 2 Punkten notwendig.", "");
          fc.addMessage("", fm);
          id = id.replace("%1%", String.valueOf(i)).replace("%2%", "G1");
          uic = component.getClientId();
          if (uic != null)
          {
             uii = (UIInput) uic;
             uii.setValid(false);
          }
    
    }
    

    } }

  2. Define your validator on the component

    <pe:inputNumber id="inV1" validator="#{myValidator}" value="#{dtSpiErf2.satz1Verloren}"
                               maxlength="2" decimalPlaces="0"
                               style="width:20px; text-align:left">
    
  3. Attach a <prime:message/> to the component and let JSF do it's work. The styling and positioning is up to you

    <prime:message for="inV1"/>
    

Upvotes: 1

Related Questions