Fixed #508 - Edit and Sort combination support for Table

pull/1196/head^2
mertsincan 2021-05-17 02:00:53 +03:00
parent dabc67877b
commit aed0d5eed2
6 changed files with 77 additions and 40 deletions

View File

@ -497,6 +497,17 @@ const DataTableEvents = [
} }
] ]
}, },
{
name: "value-change",
description: "Invoked after filtering, sorting, pagination and cell editing to pass the rendered value.",
arguments: [
{
name: "value",
type: "array",
description: "Value displayed by the table."
}
]
},
{ {
name: "row-click", name: "row-click",
description: "Callback to invoke when a row is clicked.", description: "Callback to invoke when a row is clicked.",

View File

@ -39,7 +39,7 @@ import Ripple from 'primevue/ripple';
export default { export default {
name: 'BodyCell', name: 'BodyCell',
emits: ['cell-edit-init', 'cell-edit-complete', 'cell-edit-cancel', 'row-edit-init', 'row-edit-save', 'row-edit-cancel', emits: ['cell-edit-init', 'cell-edit-complete', 'cell-edit-cancel', 'row-edit-init', 'row-edit-save', 'row-edit-cancel', 'editing-cell-change',
'row-toggle', 'radio-change', 'checkbox-change'], 'row-toggle', 'radio-change', 'checkbox-change'],
props: { props: {
rowData: { rowData: {
@ -54,6 +54,10 @@ export default {
type: Boolean, type: Boolean,
default: false default: false
}, },
rowIndex: {
type: Number,
default: null
},
index: { index: {
type: Number, type: Number,
default: null default: null
@ -153,6 +157,7 @@ export default {
switchCellToViewMode() { switchCellToViewMode() {
this.d_editing = false; this.d_editing = false;
this.unbindDocumentEditListener(); this.unbindDocumentEditListener();
this.$emit('editing-cell-change', {rowIndex: this.rowIndex, cellIndex: this.index, editing: false});
OverlayEventBus.off('overlay-click', this.overlayEventListener); OverlayEventBus.off('overlay-click', this.overlayEventListener);
this.overlayEventListener = null; this.overlayEventListener = null;
}, },
@ -163,7 +168,8 @@ export default {
if (!this.d_editing) { if (!this.d_editing) {
this.d_editing = true; this.d_editing = true;
this.bindDocumentEditListener(); this.bindDocumentEditListener();
this.$emit('cell-edit-init', {originalEvent: event, data: this.rowData, field: this.columnProp('field'), index: this.index}); this.$emit('cell-edit-init', {originalEvent: event, data: this.rowData, field: this.columnProp('field'), index: this.rowIndex});
this.$emit('editing-cell-change', {rowIndex: this.rowIndex, cellIndex: this.index, editing: true});
this.overlayEventListener = (e) => { this.overlayEventListener = (e) => {
if (this.$el && this.$el.contains(e.target)) { if (this.$el && this.$el.contains(e.target)) {
@ -179,7 +185,7 @@ export default {
originalEvent: event, originalEvent: event,
data: this.rowData, data: this.rowData,
field: this.columnProp('field'), field: this.columnProp('field'),
index: this.index, index: this.rowIndex,
type: type, type: type,
defaultPrevented: false, defaultPrevented: false,
preventDefault: function() { preventDefault: function() {
@ -202,7 +208,7 @@ export default {
case 27: case 27:
this.switchCellToViewMode(); this.switchCellToViewMode();
this.$emit('cell-edit-cancel', {originalEvent: event, data: this.rowData, field: this.columnProp('field'), index: this.index}); this.$emit('cell-edit-cancel', {originalEvent: event, data: this.rowData, field: this.columnProp('field'), index: this.rowIndex});
break; break;
case 9: case 9:
@ -291,13 +297,13 @@ export default {
return (DomHandler.find(this.$el, '.p-invalid').length === 0); return (DomHandler.find(this.$el, '.p-invalid').length === 0);
}, },
onRowEditInit(event) { onRowEditInit(event) {
this.$emit('row-edit-init', {originalEvent: event, data: this.rowData, field: this.columnProp('field'), index: this.index}); this.$emit('row-edit-init', {originalEvent: event, data: this.rowData, field: this.columnProp('field'), index: this.rowIndex});
}, },
onRowEditSave(event) { onRowEditSave(event) {
this.$emit('row-edit-save', {originalEvent: event, data: this.rowData, field: this.columnProp('field'), index: this.index}); this.$emit('row-edit-save', {originalEvent: event, data: this.rowData, field: this.columnProp('field'), index: this.rowIndex});
}, },
onRowEditCancel(event) { onRowEditCancel(event) {
this.$emit('row-edit-cancel', {originalEvent: event, data: this.rowData, field: this.columnProp('field'), index: this.index}); this.$emit('row-edit-cancel', {originalEvent: event, data: this.rowData, field: this.columnProp('field'), index: this.rowIndex});
}, },
updateStickyPosition() { updateStickyPosition() {
if (this.columnProp('frozen')) { if (this.columnProp('frozen')) {
@ -335,9 +341,6 @@ export default {
let columnStyle = this.columnProp('style'); let columnStyle = this.columnProp('style');
return this.columnProp('frozen') ? [columnStyle, bodyStyle, this.styleObject]: [columnStyle, bodyStyle]; return this.columnProp('frozen') ? [columnStyle, bodyStyle, this.styleObject]: [columnStyle, bodyStyle];
},
eventBusKey() {
return this.columnProp('field') + '_' + this.index;
} }
}, },
components: { components: {

View File

@ -67,6 +67,7 @@ declare class DataTable {
$emit(eventName: 'page', event: Event): this; $emit(eventName: 'page', event: Event): this;
$emit(eventName: 'sort', event: Event): this; $emit(eventName: 'sort', event: Event): this;
$emit(eventName: 'filter', event: Event): this; $emit(eventName: 'filter', event: Event): this;
$emit(eventName: 'value-change', value: any[]): this;
$emit(eventName: 'row-click', event: Event): this; $emit(eventName: 'row-click', event: Event): this;
$emit(eventName: 'row-dblclick', event: Event): this; $emit(eventName: 'row-dblclick', event: Event): this;
$emit(eventName: 'row-contextmenu', event: Event): this; $emit(eventName: 'row-contextmenu', event: Event): this;

View File

@ -32,7 +32,7 @@
@row-mousedown="onRowMouseDown" @row-dragstart="onRowDragStart($event)" @row-dragover="onRowDragOver($event)" @row-dragleave="onRowDragLeave($event)" @row-dragend="onRowDragEnd($event)" @row-drop="onRowDrop($event)" @row-mousedown="onRowMouseDown" @row-dragstart="onRowDragStart($event)" @row-dragover="onRowDragOver($event)" @row-dragleave="onRowDragLeave($event)" @row-dragend="onRowDragEnd($event)" @row-drop="onRowDrop($event)"
@row-toggle="toggleRow($event)" @radio-change="toggleRowWithRadio($event)" @checkbox-change="toggleRowWithCheckbox($event)" @row-toggle="toggleRow($event)" @radio-change="toggleRowWithRadio($event)" @checkbox-change="toggleRowWithCheckbox($event)"
@cell-edit-init="onCellEditInit($event)" @cell-edit-complete="onCellEditComplete($event)" @cell-edit-cancel="onCellEditCancel($event)" @cell-edit-init="onCellEditInit($event)" @cell-edit-complete="onCellEditComplete($event)" @cell-edit-cancel="onCellEditCancel($event)"
@row-edit-init="onRowEditInit($event)" @row-edit-save="onRowEditSave($event)" @row-edit-cancel="onRowEditCancel($event)"/> @row-edit-init="onRowEditInit($event)" @row-edit-save="onRowEditSave($event)" @row-edit-cancel="onRowEditCancel($event)" @editing-cell-change="onEditingCellChange($event)"/>
<DTTableBody :value="dataToRender" :columns="columns" :empty="empty" :dataKey="dataKey" :selection="selection" :selectionKeys="d_selectionKeys" :selectionMode="selectionMode" :contextMenu="contextMenu" :contextMenuSelection="contextMenuSelection" <DTTableBody :value="dataToRender" :columns="columns" :empty="empty" :dataKey="dataKey" :selection="selection" :selectionKeys="d_selectionKeys" :selectionMode="selectionMode" :contextMenu="contextMenu" :contextMenuSelection="contextMenuSelection"
:rowGroupMode="rowGroupMode" :groupRowsBy="groupRowsBy" :expandableRowGroups="expandableRowGroups" :rowClass="rowClass" :editMode="editMode" :compareSelectionBy="compareSelectionBy" :scrollable="scrollable" :rowGroupMode="rowGroupMode" :groupRowsBy="groupRowsBy" :expandableRowGroups="expandableRowGroups" :rowClass="rowClass" :editMode="editMode" :compareSelectionBy="compareSelectionBy" :scrollable="scrollable"
:expandedRowIcon="expandedRowIcon" :collapsedRowIcon="collapsedRowIcon" :expandedRows="expandedRows" :expandedRowKeys="d_expandedRowKeys" :expandedRowGroups="expandedRowGroups" :expandedRowIcon="expandedRowIcon" :collapsedRowIcon="collapsedRowIcon" :expandedRows="expandedRows" :expandedRowKeys="d_expandedRowKeys" :expandedRowGroups="expandedRowGroups"
@ -41,7 +41,7 @@
@row-mousedown="onRowMouseDown" @row-dragstart="onRowDragStart($event)" @row-dragover="onRowDragOver($event)" @row-dragleave="onRowDragLeave($event)" @row-dragend="onRowDragEnd($event)" @row-drop="onRowDrop($event)" @row-mousedown="onRowMouseDown" @row-dragstart="onRowDragStart($event)" @row-dragover="onRowDragOver($event)" @row-dragleave="onRowDragLeave($event)" @row-dragend="onRowDragEnd($event)" @row-drop="onRowDrop($event)"
@row-toggle="toggleRow($event)" @radio-change="toggleRowWithRadio($event)" @checkbox-change="toggleRowWithCheckbox($event)" @row-toggle="toggleRow($event)" @radio-change="toggleRowWithRadio($event)" @checkbox-change="toggleRowWithCheckbox($event)"
@cell-edit-init="onCellEditInit($event)" @cell-edit-complete="onCellEditComplete($event)" @cell-edit-cancel="onCellEditCancel($event)" @cell-edit-init="onCellEditInit($event)" @cell-edit-complete="onCellEditComplete($event)" @cell-edit-cancel="onCellEditCancel($event)"
@row-edit-init="onRowEditInit($event)" @row-edit-save="onRowEditSave($event)" @row-edit-cancel="onRowEditCancel($event)"/> @row-edit-init="onRowEditInit($event)" @row-edit-save="onRowEditSave($event)" @row-edit-cancel="onRowEditCancel($event)" @editing-cell-change="onEditingCellChange($event)"/>
<DTTableFooter :columnGroup="footerColumnGroup" :columns="columns" /> <DTTableFooter :columnGroup="footerColumnGroup" :columns="columns" />
</table> </table>
</div> </div>
@ -73,11 +73,11 @@ import TableFooter from './TableFooter.vue';
export default { export default {
name: 'DataTable', name: 'DataTable',
emits: ['update:first', 'update:rows', 'page', 'update:sortField', 'update:sortOrder', 'update:multiSortMeta', 'sort', 'filter', 'row-click', 'row-dblclick', emits: ['value-change', 'update:first', 'update:rows', 'page', 'update:sortField', 'update:sortOrder', 'update:multiSortMeta', 'sort', 'filter', 'row-click', 'row-dblclick',
'update:selection', 'row-select', 'row-unselect', 'update:contextMenuSelection', 'row-contextmenu', 'row-unselect-all', 'row-select-all', 'update:selection', 'row-select', 'row-unselect', 'update:contextMenuSelection', 'row-contextmenu', 'row-unselect-all', 'row-select-all',
'column-resize-end', 'column-reorder', 'row-reorder', 'update:expandedRows', 'row-collapse', 'row-expand', 'column-resize-end', 'column-reorder', 'row-reorder', 'update:expandedRows', 'row-collapse', 'row-expand',
'update:expandedRowGroups', 'rowgroup-collapse', 'rowgroup-expand', 'update:filters', 'state-restore', 'state-save', 'update:expandedRowGroups', 'rowgroup-collapse', 'rowgroup-expand', 'update:filters', 'state-restore', 'state-save',
'cell-edit-init', 'cell-edit-complete', 'cell-edit-cancel', 'update:editingRows', 'row-edit-init', 'row-edit-save', 'row-edit-cancel'], 'cell-edit-init', 'cell-edit-complete', 'cell-edit-cancel', 'update:editingRows', 'row-edit-init', 'row-edit-save', 'row-edit-cancel', 'editing-cell-change'],
props: { props: {
value: { value: {
type: Array, type: Array,
@ -323,7 +323,8 @@ export default {
d_expandedRowKeys: null, d_expandedRowKeys: null,
d_columnOrder: null, d_columnOrder: null,
d_editingRowKeys: null, d_editingRowKeys: null,
d_filters: this.cloneFilters(this.filters) d_filters: this.cloneFilters(this.filters),
editingCells: []
}; };
}, },
rowTouched: false, rowTouched: false,
@ -425,6 +426,7 @@ export default {
this.$emit('update:first', this.d_first); this.$emit('update:first', this.d_first);
this.$emit('update:rows', this.d_rows); this.$emit('update:rows', this.d_rows);
this.$emit('page', pageEvent); this.$emit('page', pageEvent);
this.$emit('value-change', this.processedData);
}, },
onColumnHeaderClick(e) { onColumnHeaderClick(e) {
const event = e.originalEvent; const event = e.originalEvent;
@ -468,6 +470,7 @@ export default {
} }
this.$emit('sort', this.createLazyLoadEvent(event)); this.$emit('sort', this.createLazyLoadEvent(event));
this.$emit('value-change', this.processedData);
} }
} }
}, },
@ -613,6 +616,7 @@ export default {
let filterEvent = this.createLazyLoadEvent(); let filterEvent = this.createLazyLoadEvent();
filterEvent.filteredValue = filteredValue; filterEvent.filteredValue = filteredValue;
this.$emit('filter', filterEvent); this.$emit('filter', filterEvent);
this.$emit('value-change', this.processedData);
return filteredValue; return filteredValue;
}, },
@ -1520,6 +1524,18 @@ export default {
onCellEditCancel(event) { onCellEditCancel(event) {
this.$emit('cell-edit-cancel', event); this.$emit('cell-edit-cancel', event);
}, },
onEditingCellChange(event) {
let { rowIndex, cellIndex, editing } = event;
let _editingCells = [...this.editingCells];
if (editing)
_editingCells.push({ rowIndex, cellIndex });
else
_editingCells = _editingCells.filter(cell => !(cell.rowIndex === rowIndex && cell.cellIndex === cellIndex));
this.editingCells = _editingCells;
this.$emit('value-change', this.processedData);
},
onRowEditInit(event) { onRowEditInit(event) {
let _editingRows = this.editingRows ? [...this.editingRows] : []; let _editingRows = this.editingRows ? [...this.editingRows] : [];
_editingRows.push(event.data); _editingRows.push(event.data);
@ -1708,14 +1724,14 @@ export default {
hasFilters() { hasFilters() {
return this.filters && Object.keys(this.filters).length > 0 && this.filters.constructor === Object; return this.filters && Object.keys(this.filters).length > 0 && this.filters.constructor === Object;
}, },
hasEditingCell() {
return this.editingCells && this.editingCells.length !== 0;
},
processedData() { processedData() {
if (this.lazy) { let data = this.value || [];
return this.value || [];
}
else {
if (this.value && this.value.length) {
let data = this.value;
if (!this.lazy && !this.hasEditingCell) {
if (data && data.length) {
if (this.sorted) { if (this.sorted) {
if(this.sortMode === 'single') if(this.sortMode === 'single')
data = this.sortSingle(data); data = this.sortSingle(data);
@ -1726,12 +1742,10 @@ export default {
if (this.hasFilters) { if (this.hasFilters) {
data = this.filter(data); data = this.filter(data);
} }
return data;
} }
return [];
} }
return data;
}, },
dataToRender() { dataToRender() {
const data = this.processedData; const data = this.processedData;

View File

@ -15,13 +15,13 @@
@click="onRowClick($event, rowData, index)" @dblclick="onRowDblClick($event, rowData, index)" @contextmenu="onRowRightClick($event, rowData, index)" @touchend="onRowTouchEnd($event)" @keydown="onRowKeyDown($event, rowData, index)" :tabindex="selectionMode || contextMenu ? '0' : null" @click="onRowClick($event, rowData, index)" @dblclick="onRowDblClick($event, rowData, index)" @contextmenu="onRowRightClick($event, rowData, index)" @touchend="onRowTouchEnd($event)" @keydown="onRowKeyDown($event, rowData, index)" :tabindex="selectionMode || contextMenu ? '0' : null"
@mousedown="onRowMouseDown($event)" @dragstart="onRowDragStart($event, index)" @dragover="onRowDragOver($event,index)" @dragleave="onRowDragLeave($event)" @dragend="onRowDragEnd($event)" @drop="onRowDrop($event)" role="row"> @mousedown="onRowMouseDown($event)" @dragstart="onRowDragStart($event, index)" @dragover="onRowDragOver($event,index)" @dragleave="onRowDragLeave($event)" @dragend="onRowDragEnd($event)" @drop="onRowDrop($event)" role="row">
<template v-for="(col,i) of columns" :key="columnProp(col,'columnKey')||columnProp(col,'field')||i"> <template v-for="(col,i) of columns" :key="columnProp(col,'columnKey')||columnProp(col,'field')||i">
<DTBodyCell v-if="shouldRenderBodyCell(value, col, index)" :rowData="rowData" :column="col" :index="index" :selected="isSelected(rowData)" <DTBodyCell v-if="shouldRenderBodyCell(value, col, index)" :rowData="rowData" :column="col" :rowIndex="index" :index="i" :selected="isSelected(rowData)"
:rowTogglerIcon="columnProp(col,'expander') ? rowTogglerIcon(rowData): null" :frozenRow="frozenRow" :rowTogglerIcon="columnProp(col,'expander') ? rowTogglerIcon(rowData): null" :frozenRow="frozenRow"
:rowspan="rowGroupMode === 'rowspan' ? calculateRowGroupSize(value, col, index) : null" :rowspan="rowGroupMode === 'rowspan' ? calculateRowGroupSize(value, col, index) : null"
:editMode="editMode" :editing="editMode === 'row' && isRowEditing(rowData)" :responsiveLayout="responsiveLayout" :editMode="editMode" :editing="editMode === 'row' && isRowEditing(rowData)" :responsiveLayout="responsiveLayout"
@radio-change="onRadioChange($event)" @checkbox-change="onCheckboxChange($event)" @row-toggle="onRowToggle($event)" @radio-change="onRadioChange($event)" @checkbox-change="onCheckboxChange($event)" @row-toggle="onRowToggle($event)"
@cell-edit-init="onCellEditInit($event)" @cell-edit-complete="onCellEditComplete($event)" @cell-edit-cancel="onCellEditCancel($event)" @cell-edit-init="onCellEditInit($event)" @cell-edit-complete="onCellEditComplete($event)" @cell-edit-cancel="onCellEditCancel($event)"
@row-edit-init="onRowEditInit($event)" @row-edit-save="onRowEditSave($event)" @row-edit-cancel="onRowEditCancel($event)"/> @row-edit-init="onRowEditInit($event)" @row-edit-save="onRowEditSave($event)" @row-edit-cancel="onRowEditCancel($event)" @editing-cell-change="onEditingCellChange($event)"/>
</template> </template>
</tr> </tr>
<tr class="p-datatable-row-expansion" v-if="templates['expansion'] && expandedRows && isRowExpanded(rowData)" :key="getRowKey(rowData, index) + '_expansion'" role="row"> <tr class="p-datatable-row-expansion" v-if="templates['expansion'] && expandedRows && isRowExpanded(rowData)" :key="getRowKey(rowData, index) + '_expansion'" role="row">
@ -52,7 +52,7 @@ export default {
emits: ['rowgroup-toggle', 'row-click', 'row-dblclick', 'row-rightclick', 'row-touchend', 'row-keydown', 'row-mousedown', emits: ['rowgroup-toggle', 'row-click', 'row-dblclick', 'row-rightclick', 'row-touchend', 'row-keydown', 'row-mousedown',
'row-dragstart', 'row-dragover', 'row-dragleave', 'row-dragend', 'row-drop', 'row-toggle', 'row-dragstart', 'row-dragover', 'row-dragleave', 'row-dragend', 'row-drop', 'row-toggle',
'radio-change', 'checkbox-change', 'cell-edit-init', 'cell-edit-complete', 'cell-edit-cancel', 'radio-change', 'checkbox-change', 'cell-edit-init', 'cell-edit-complete', 'cell-edit-cancel',
'row-edit-init', 'row-edit-save', 'row-edit-cancel'], 'row-edit-init', 'row-edit-save', 'row-edit-cancel', 'editing-cell-change'],
props: { props: {
value: { value: {
type: Array, type: Array,
@ -447,6 +447,9 @@ export default {
onRowEditCancel(event) { onRowEditCancel(event) {
this.$emit('row-edit-cancel', event); this.$emit('row-edit-cancel', event);
}, },
onEditingCellChange(event) {
this.$emit('editing-cell-change', event);
},
updateFrozenRowStickyPosition() { updateFrozenRowStickyPosition() {
this.$el.style.top = DomHandler.getOuterHeight(this.$el.previousElementSibling) + 'px'; this.$el.style.top = DomHandler.getOuterHeight(this.$el.previousElementSibling) + 'px';
}, },

View File

@ -2234,6 +2234,11 @@ export default {
</td> </td>
<td>Event to emit after filtering, not triggered in lazy mode.</td> <td>Event to emit after filtering, not triggered in lazy mode.</td>
</tr> </tr>
<tr>
<td>value-change</td>
<td>value: Value displayed by the table</td>
<td>Callback to invoke after filtering, sorting, pagination and cell editing to pass the rendered value.</td>
</tr>
<tr> <tr>
<td>row-click</td> <td>row-click</td>
<td>event.originalEvent: Browser event. <br /> <td>event.originalEvent: Browser event. <br />