简体   繁体   中英

JSF PrimeFaces - Save value of selected tablecell on buttonclick

Prerequisites:

  • JSF 2.1
  • Primefaces 5.2
  • Glassfish 3.1

Story:

I got a datatable displaying some editable values. The amount of columns is dynamic. In the same form is a button calling a save-action of my bean to save all edited data. The function it self is working perfectly fine

Implementation:

<p:dataTable id="dataTable" scrollable="true"
    widgetVar="wigVardataTable"
    value="#{myBean.dataList}"
    var="data"
    editable="true"
    editMode="cell"
    rowKey="rowkey">        
   <p:columns var="col"
     value="#{myModel.columnList}"
     style="font-size: 12px">
     <f:facet name="header">
        <h:outputText
          value="#{col.header}" />
     </f:facet>
     <p:cellEditor>
        <f:facet name="output">
          <h:outputText
            value="#{myModel.getValueForTableCell(data, col).value}" />
        </f:facet>
          <f:facet name="input">
            <p:inputText
              id="inputTxt"
              value="#{myModel.getValueForTableCell(data, col).value}"
              style="width:100%">       
            </p:inputText>
        </f:facet>
      </p:cellEditor>
    </p:columns>
  </p:dataTable>

Problem:

When pressing the save button while a table cell is being edited and didn't loose its focus yet, the new value inside the inputtext of the tablecell won't be written back into my bean and due to that won't be saved.

Question:

How can i write back the data into my backing bean, before the button action is executed?

This behavior is caused by wrong ordering of ajax events. When the command button is invoked while having a cell editor open, then the ajax event of the command button is fired before the ajax event of the cell edit.

We'd thus like to swap around them. Without editing the PrimeFaces source code, you could achieve this by explicitly invoking saveCell() function of the <p:dataTable> widget when there's a cell editor open.

So, given a

<h:form>
    <p:dataTable ... widgetVar="wigVardataTable" />
    <p:commandButton ... />
</h:form>

you can achieve the desired behavior by adding the below onclick to the <p:commandButton> :

onclick="var d=PF('wigVardataTable'), c=d.jq.find('td:has(.ui-cell-editor-input:visible)'); if(c.length)d.saveCell(c)"

Basically, it first finds the cell with an open cell editor and then invokes saveCell() on it.

Another, less elegant, way is explicitly invoking showCellEditor() function of the <p:dataTable> widget without passing the expected target cell in a try-catch block where the exception is ignored.

onclick="try{PF('wigVardataTable').showCellEditor()}catch(ignore){}"

It will save any opened cell first and later throw an error that no new target cell was specified as argument, but that could be ignored as shown above.


Noted should be that this all works regardless of whether you use <p:columns> or <p:column> , and also regardless of whether you use a normal model or an overcomplicated model ;) This trick is tested on both your PrimeFaces 5.2 version and the current PrimeFaces 6.0 version.

Here is a generic solution inspired by BalusC answer if you have other datatables with cell editMode :

<script type="application/javascript">
    function saveAllCellsBeforeSubmit() {
        for (var widgetName in PrimeFaces.widgets) {
            if (PrimeFaces.widgets[widgetName].hasOwnProperty('cfg') &amp;&amp; PrimeFaces.widgets[widgetName].cfg.hasOwnProperty('editMode') &amp;&amp; PrimeFaces.widgets[widgetName].cfg.editMode === 'cell') {
                var d = PF(widgetName);
                var c = d.jq.find('td:has(.ui-cell-editor-input:visible)');
                if (c.length) {
                    d.saveCell(c);
                }
            }
        }
    }
</script>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM