Primefaces datatable roweditor: only permit one ro

2020-02-19 06:53发布

I'm working with JSF 2.1.6 and Primefaces 3.4.1 and I have a question.

I have an editable datatable with row editor. You can click the pencil button of each row, and the row will be editable. But by default it's possible to click many pencil button, and for this reason many rows will be editable.

But I want only one row in edit mode.

This is a sample of my code:

<p:dataTable value="rows" var="row" editable="true" 
 id="myTable" widgetVar="myTableVar" styleClass="myTableStyle">

    <p:ajax event="rowEdit" listener="#{myBean.onUpdateRow}" />
    <p:ajax event="rowEditCancel" />

    <p:columnGroup type="header">
        <p:column headerText="Name" />
        <p:column headerText="Age" />
        ...
        <p:column headerText="Edit" />
    </p:columnGroup>

    <p:column>
        <p:cellEditor>
        <f:facet name="output">
                <h:outputText value="#{row.name}" />
            </f:facet>
            <f:facet name="output">
                 <h:inputText value="#{row.name}" /> 
            </f:facet>
        </p:cellEditor>
    </p:column>

    <p:column>
        <p:cellEditor>
        <f:facet name="output">
                <h:outputText value="#{row.age}" />
            </f:facet>
            <f:facet name="output">
                 <h:inputText value="#{row.age}" /> 
            </f:facet>
        </p:cellEditor>
    </p:column>

    ...

    <p:column>
        <p:commandLink update="myTable">
            <p:rowEditor />
        </p:commandLink>
    </p:column>

</p:dataTable>

<p:commandButton icon="ui-icon-plus" action="#{myBean.addNewRow}" update="myTable"
 oncomplete="$('.myTableStyle tbody.ui-datatable-data tr:last-child td span.ui-row-editor span.ui-icon-pencil').click()"
 title="Add new row" />

I've encapsulated the row editor component in a command link component, because now I can add Javascript code when clicking the row editor.

I've tried adding this Javascript code to the commandLink:

onclick="$('.myTableStyle tbody.ui-datatable-data tr td span.ui-row-editor span.ui-icon-cancel').click()"

But this create so much recursion and not works.

The row editor has three span links: one for open the edit mode (ui-icon-pencil), other that saves the edition (ui-icon-check), and other that cancel the edition (ui-icon-close). Ther is an ajax event for saving (rowEdit), and other event for cancelling (rowEditCancel).

Files where edit mode is not activated, the row editor spans like this:

<span class="ui-icon ui-icon-pencil"></span>
<span class="ui-icon ui-icon-check" style="display:none"></span>
<span class="ui-icon ui-icon-close" style="display:none"></span>

And files where edit mode is activated the row editor spans like this:

 <span class="ui-icon ui-icon-pencil" style="display:none"></span>
 <span class="ui-icon ui-icon-check"></span>
 <span class="ui-icon ui-icon-close"></span>

So, how can I click only the rows where edit mode is activated? Or there is a function or property to permit only one row in edit mode? Can I click only with jQuery the spans with icon ui-icon-close when that span has display inline, and not the others with display none?

Update: Solution I have Found

I've just found a homemade solution. Here it is: I've added a onstart function to the link, but this generates a performance issue: it's called both as to save, to edit, and to cancel. And also I've changed the oncomplete function of the add row button.

<p:dataTable value="rows" var="row" editable="true" 
 id="myTable" widgetVar="myTableVar" styleClass="myTableStyle">

    <p:ajax event="rowEdit" listener="#{myBean.onUpdateRow}" />
    <p:ajax event="rowEditCancel" />

    <p:columnGroup type="header">
        <p:column headerText="Name" />
        <p:column headerText="Age" />
        ...
        <p:column headerText="Edit" />
    </p:columnGroup>

    <p:column>
        <p:cellEditor>
        <f:facet name="output">
                <h:outputText value="#{row.name}" />
            </f:facet>
            <f:facet name="output">
                 <h:inputText value="#{row.name}" /> 
            </f:facet>
        </p:cellEditor>
    </p:column>

    <p:column>
        <p:cellEditor>
        <f:facet name="output">
                <h:outputText value="#{row.age}" />
            </f:facet>
            <f:facet name="output">
                 <h:inputText value="#{row.age}" /> 
            </f:facet>
        </p:cellEditor>
    </p:column>

    ...

    <p:column>
        <p:commandLink update="myTable" onstart="$('.myTableStyle tbody.ui-datatable-data tr td .ui-cell-editor-input').hide(); $('.myTableStyle tbody.ui-datatable-data tr td .ui-cell-editor-output').show(); $('.myTableStyle tbody.ui-datatable-data tr td span.ui-row-editor span.ui-icon-pencil').show();  $('.myTableStyle tbody.ui-datatable-data tr td span.ui-row-editor span.ui-icon-check').hide(); $('.myTableStyle tbody.ui-datatable-data tr td span.ui-row-editor span.ui-icon-close').hide(); $('.myTableStyle tbody.ui-datatable-data tr').removeClass('ui-state-highlight'); return false;">
            <p:rowEditor />
        </p:commandLink>
    </p:column>

</p:dataTable>

<p:commandButton icon="ui-icon-plus" action="#{myBean.addNewRow}" update="myTable"
 oncomplete="$('.myTableStyle tbody.ui-datatable-data tr:last-child td .ui-cell-editor-input').show(); $('.myTableStyle tbody.ui-datatable-data tr:last-child td .ui-cell-editor-output').hide(); $('.myTableStyle tbody.ui-datatable-data tr:last-child td span.ui-row-editor span.ui-icon-pencil').hide();  $('.myTableStyle tbody.ui-datatable-data tr:last-child  td span.ui-row-editor span.ui-icon-check').show(); $('.myTableStyle tbody.ui-datatable-data tr:last-child  td span.ui-row-editor span.ui-icon-close').show(); $('.myTableStyle tbody.ui-datatable-data tr:last-child').addClass('ui-state-highlight'); return false;
 title="Add new row" />

Update-2: Finally I found a solution to the performance issue. My problem was that the Javascript action was called when clicking to edit, save and cancel the row edition. To prevent that, I changed the onstart function to an onclick function that changes the other rows to non editable only when clicking the edit row button (pencil icon). To do that I use event.target, to know what element has clicked. As row edit, row edit save and row edit cancel button has different classes (ui-icon-pencil, ui-icon-check and ui-icon-close), it can be possible you can differentiate which button was pressed. So this is the function that replaces the onstart function:

onclick="$(if($(event.target).hasClass('ui-icon-pencil')) {'.myTableStyle tbody.ui-datatable-data tr td .ui-cell-editor-input').hide(); $('.myTableStyle tbody.ui-datatable-data tr td .ui-cell-editor-output').show(); $('.myTableStyle tbody.ui-datatable-data tr td span.ui-row-editor span.ui-icon-pencil').show(); $('.myTableStyle tbody.ui-datatable-data tr td span.ui-row-editor span.ui-icon-check').hide(); $('.myTableStyle tbody.ui-datatable-data tr td span.ui-row-editor span.ui-icon-close').hide(); $('.myTableStyle tbody.ui-datatable-data tr').removeClass('ui-state-highlight');} return false;"

2条回答
够拽才男人
2楼-- · 2020-02-19 07:49

You need to iterate through the elements, and cancel any other edit.

$('.myTableStyle tbody.ui-datatable-data tr td span.ui-row-editor span.ui-icon-cancel').each(function(){
  $(this).click();
});
查看更多
干净又极端
3楼-- · 2020-02-19 07:52

The above solution is not working for me. As an alternativ solution, I just hide the edit-button (pencil) when I'm editing a row with css

<p:ajax event="rowEditInit" oncomplete="$('.ui-row-editor span.ui-icon-pencil').each(function(){$(this).css('visibility','hidden')});" />

<p:ajax event="rowEdit" oncomplete="$('.ui-row-editor span.ui-icon-pencil').each(function(){$(this).css('visibility','visible')});"/>   

<p:ajax event="rowEditCancel" onstart="$('.ui-row-editor span.ui-icon-pencil').each(function(){$(this).css('visibility','visible')});"/>
查看更多
登录 后发表回答