Search code examples
jsfprimefacesdatatabletablecelleditor

p:dataTable with p:cellEditor tab behaviour


I have the follwing datatable structure:

<p:dataTable editable="true" editMode="cell"..>

<p:column headerText="value_1">
  <p:cellEditor>
      <f:facet name="output">
         <h:outputText ...
      </f:facet>
      <f:facet name="input">
         <p:inputText ....
      </f:facet>
  </p:cellEditor>
</p:column>
<p:column headerText="value_2">
  <p:cellEditor>
      <f:facet name="output">
         <h:outputText ...
      </f:facet>
      <f:facet name="input">
         <p:inputText ....
      </f:facet>
  </p:cellEditor>
</p:column>
<p:column headerText="action">
  <p:commandButton tabindex="-1"...
</p:column>

The problem is that the last column breaks the tab-navigation. I can tab from column1 to column2 but cannot reach the next row. When I remove the last column everything works as expected. I want a tab-behaviour like this:

row1_column1 -> row1_column2 -> row2_column1 -> row2_column2 -> ....

I also tried to remove tabindex="-1" and use a p:cellEditor in the third column, but the behaviour stays the same, I can only tab in row1. What am I missing?

I'm using Primefaces version 6.0


Solution

  • The PrimeFaces data table cell editor tab behavior is implemented here:

    2243    tabCell: function(cell, forward) {
    2244        var targetCell = forward ? cell.next() : cell.prev();
    2245        if(targetCell.length == 0) {
    2246            var tabRow = forward ? cell.parent().next() : cell.parent().prev();
    2247            targetCell = forward ? tabRow.children('td.ui-editable-column:first') : tabRow.children('td.ui-editable-column:last');
    2248        }
    2249
    2250        this.showCellEditor(targetCell);
    2251    },
    

    Check line 2244. The next() and prev() calls do not check whether it's a .ui-editable-column. So it basically blindly tabs into any column even if it doesn't contain a <p:cellEditor>.

    We thus want to fix exactly that part to check for .ui-editable-column. Put the below code in a JS file.

    if (PrimeFaces.widget.DataTable) {
        PrimeFaces.widget.DataTable = PrimeFaces.widget.DataTable.extend({
            tabCell: function(cell, forward) {
                var targetCell = forward ? cell.next('td.ui-editable-column') : cell.prev('td.ui-editable-column');
                if(targetCell.length == 0) {
                    var tabRow = forward ? cell.parent().next() : cell.parent().prev();
                    targetCell = forward ? tabRow.children('td.ui-editable-column:first') : tabRow.children('td.ui-editable-column:last');
                }
    
                this.showCellEditor(targetCell);
            }
        });
    }
    

    Make sure that this JS file is loaded after PrimeFaces own JS. The best place for that is shown below:

    <h:head>
        ...
    </h:head>
    <h:body>
        <h:outputScript name="primefaces-patches.js" target="head" />
        ...
    </h:body>
    

    See also: