How to get row index of currently validating row in p:dataTable?

I'm making a p:dataTable for users' ip ranges with cellEditors, which consist of p:inputMask. The dataTable consists of 2 editable columns. To validate I have to:

  1. Check whether the specified ip-adress matches the RegEx,
  2. Ensure that start of the range is actually before than the finish,
  3. Ensure that specified range is not intersecting with previously entered ranges.

First two parts didn't make much noise. The third one required me to check if the specified range is before or after previously entered ranges. You just check start and finish to be both either before or after every other ip range. Easy, right?

The validating cycle.

    for (Groupip gip : searchResults) {
        long ipend = ipToLong(InetAddress.getByName(gip.getIpend()));
        long ipstart = ipToLong(InetAddress.getByName(gip.getIpstart()));
        boolean validLeft = true, validRight = true;
        validLeft = validLeft && ipstart < ipValidated;
        validLeft = validLeft && ipend < ipValidated;
        validLeft = validLeft && ipstart < ipValidating;
        validLeft = validLeft && ipend < ipValidating;
        validRight = validRight && ipstart > ipValidated;
        validRight = validRight && ipend > ipValidated;
        validRight = validRight && ipstart > ipValidating;
        validRight = validRight && ipend > ipValidating;
        if (validLeft || validRight) {
            //OK
        } else {
            //ERROR
        }
    }

The dataTable.

    <p:dataTable id="ips1" widgetVar="ips1" var="ip" value="#{groupipController.searchResults}" editable="true"
                 rowKey="#{ip.groupcode}-#{ip.ipstart}-#{ip.ipend}" selection="#{groupipController.selected}" selectionMode="single"
                 >
        <f:facet name="header">
            Диапазон IP
        </f:facet>
        <p:ajax event="rowEditCancel" listener="#{groupipController.onRowCancel}" />
        <p:ajax event="rowEditInit" listener="#{groupipController.onRowEditInit}" />
        <p:ajax event="rowEdit" listener="#{groupipController.onRowEdit}" update=":form:msgs :form:ips1 :form:growlmsgs" process=":form:ips1"/>

        <p:column headerText="От" style="min-height: 16px" id='from_col'>
            <p:cellEditor>
                <f:facet name="output"><h:outputText value="#{ip.ipstart}" /></f:facet>
                <f:facet name="input">
                    <p:inputMask mask="999.999.999.999" value="#{ip.ipstart}" id="fromip" autoClear="false" slotChar="0"
                                 validator="#{groupipController.validate}"
                                 class="ui-inputfield ui-inputmask ui-widget ui-state-default ui-corner-all p-0-1 w-100 h-100"/>
                </f:facet>
            </p:cellEditor>
        </p:column>
        <p:column headerText="До" style="min-height: 16px" id='to_col'>
            <p:cellEditor>
                <f:facet name="output"><h:outputText value="#{ip.ipend}" /></f:facet>
                <f:facet name="input">
                    <p:inputMask mask="999.999.999.999" value="#{ip.ipend}" id="toip" autoClear="false" slotChar="0"
                                 validator="#{groupipController.validate}"
                                 class="ui-inputfield ui-inputmask ui-widget ui-state-default ui-corner-all p-0-1 w-100 h-100"/>  
                </f:facet>
            </p:cellEditor>
        </p:column>
        <p:column width="10%" >
            <p:rowEditor rendered="#{armgroupController.update}" />
        </p:column>
    </p:dataTable>

But there is more. The searchResults is a variable, which is the source for dataTable, that contains a List<Groupip>. But it also contains the row that is currently being edited. So I have to exclude it, or I will fail the validation, comparing the range to itself.

How do I do this exactly? The only way I could find the row index of the editting row is to get the pre-last value of the cliendId (which looks like this in the browser: form:ips1:2:toip) with this code:

if (gip == searchResults.get(Integer.parseInt(component.getClientId().split(":")[2]))) {
    continue;
}

This is not appropriate, since naming containers could change. So, I would like to know, is there another way to get row index?

Upvotes: 1

Views: 296

Answers (1)

Kukeltje
Kukeltje

Reputation: 12337

Your id of the current component is always the last one in the full clientID list and you yourself state to take the pre-last value, but effectively you take the third value (index 2)

If you'd actually get the last but one index (base-0) as the rowindex you are (mostly) always fine.

String[] fields = component.getClientId().split(":");
int index = Integer.parseInt(fields[fields.length-2]); 
if (gip == searchResults.get(index)) {
    continue;
}

If someone wraps this 'current' component in a namingcontainer, the index will not be the one but last but one before that, or even before that. So you could add this in a loop to get the first part of the split clientId that is a number, since JSF (html) id's cannot start with a number and hence cannot be a number so you are 'safe' then.

String[] fields = component.getClientId().split(":");
int indexPos = fields.length-2;
int index = -1;
do {
   try {
       index = Integer.parseInt(fields[indexPos]); 
   } catch {
       indexPos--;
   }
} while (index == -1)
if (gip == searchResults.get(index)) {
    continue;
}

You could also try to cast the parent of the component to a Datatable and see if it contains something like getCurrentRow() that could be used, but you should then also create a loop to get the parent of the parent if the parent is not a datatable.

An example to investigate is the source of http://showcase.omnifaces.org/validators/validateUniqueColumn

Upvotes: 1

Related Questions