Row and Column Reordering for DataTable

pull/104/head
cagataycivici 2019-10-17 16:56:54 +03:00
parent 2b302c7856
commit c7e328a65b
3 changed files with 144 additions and 7 deletions

View File

@ -73,6 +73,18 @@ export default {
rowspan: { rowspan: {
type: Number, type: Number,
default: null default: null
},
rowReorder: {
type: Boolean,
default: false
}
,rowReorderIcon: {
type: String,
default: 'pi pi-bars'
},
reorderableColumn: {
type: Boolean,
default: true
} }
}, },
render() { render() {

View File

@ -37,7 +37,8 @@
</tr> </tr>
<template v-else> <template v-else>
<tr v-for="(row,i) of headerColumnGroup.rows" :key="i"> <tr v-for="(row,i) of headerColumnGroup.rows" :key="i">
<th v-for="(col,i) of row.columns" :key="col.columnKey||col.field||i" :style="col.headerStyle" :class="getColumnHeaderClass(col)" @click="onColumnHeaderClick($event, col)" <th v-for="(col,i) of row.columns" :key="col.columnKey||col.field||i" :style="col.headerStyle" :class="getColumnHeaderClass(col)"
@dragstart="onColumnHeaderDragStart($event)" @dragover="onColumnHeaderDragOver($event)" @dragleave="onColumnHeaderDragLeave($event)" @drop="onColumnHeaderDrop($event)"
:colspan="col.colspan" :rowspan="col.rowspan"> :colspan="col.colspan" :rowspan="col.rowspan">
<ColumnSlot :column="col" type="header" v-if="col.$scopedSlots.header" /> <ColumnSlot :column="col" type="header" v-if="col.$scopedSlots.header" />
<span class="p-column-title" v-if="col.header">{{col.header}}</span> <span class="p-column-title" v-if="col.header">{{col.header}}</span>
@ -51,13 +52,17 @@
<tbody class="p-datatable-tbody"> <tbody class="p-datatable-tbody">
<template v-if="!empty"> <template v-if="!empty">
<tr :class="getRowClass(rowData)" v-for="(rowData, index) of dataToRender" :key="getRowKey(rowData, index)" <tr :class="getRowClass(rowData)" v-for="(rowData, index) of dataToRender" :key="getRowKey(rowData, index)"
@click="onRowClick($event, rowData, index)" @touchend="onRowTouchEnd($event)" @keydown="onRowKeyDown($event, rowData, index)" :tabindex="selectionMode ? '0' : null"> @click="onRowClick($event, rowData, index)" @touchend="onRowTouchEnd($event)" @keydown="onRowKeyDown($event, rowData, index)" :tabindex="selectionMode ? '0' : null"
@mousedown="onRowMouseDown($event)" @dragstart="onRowDragStart($event, index)" @dragover="onRowDragOver($event,index)" @dragleave="onRowDragLeave($event)" @dragend="onRowDragEnd($event)" @drop="onRowDrop($event)">
<td v-for="(col,i) of columns" :key="col.columnKey||col.field||i" :style="col.bodyStyle" :class="col.bodyClass"> <td v-for="(col,i) of columns" :key="col.columnKey||col.field||i" :style="col.bodyStyle" :class="col.bodyClass">
<ColumnSlot :data="rowData" :column="col" type="body" v-if="col.$scopedSlots.body" /> <ColumnSlot :data="rowData" :column="col" type="body" v-if="col.$scopedSlots.body" />
<template v-else-if="col.selectionMode"> <template v-else-if="col.selectionMode">
<DTRadioButton :value="rowData" :checked="isSelected(rowData)" @change="toggleRowWithRadio" v-if="col.selectionMode === 'single'" /> <DTRadioButton :value="rowData" :checked="isSelected(rowData)" @change="toggleRowWithRadio" v-if="col.selectionMode === 'single'" />
<DTCheckbox :value="rowData" :checked="isSelected(rowData)" @change="toggleRowWithCheckbox" v-else-if="col.selectionMode ==='multiple'" /> <DTCheckbox :value="rowData" :checked="isSelected(rowData)" @change="toggleRowWithCheckbox" v-else-if="col.selectionMode ==='multiple'" />
</template> </template>
<template v-else-if="col.rowReorder">
<i :class="['p-datatable-reorderablerow-handle', col.rowReorderIcon]"></i>
</template>
<template v-else>{{resolveFieldData(rowData, col.field)}}</template> <template v-else>{{resolveFieldData(rowData, col.field)}}</template>
</td> </td>
</tr> </tr>
@ -294,6 +299,9 @@ export default {
colReorderIconWidth: null, colReorderIconWidth: null,
colReorderIconHeight: null, colReorderIconHeight: null,
draggedColumn: null, draggedColumn: null,
draggedRowIndex: null,
droppedRowIndex: null,
rowDragging: null,
watch: { watch: {
first(newValue) { first(newValue) {
this.d_first = newValue; this.d_first = newValue;
@ -980,8 +988,8 @@ export default {
this.documentColumnResizeEndListener = null; this.documentColumnResizeEndListener = null;
} }
}, },
onColumnHeaderMouseDown(event) { onColumnHeaderMouseDown(event, col) {
if (this.reorderableColumns) { if (this.reorderableColumns && col.reorderableColumn) {
if (event.target.nodeName === 'INPUT' || event.target.nodeName === 'TEXTAREA' || DomHandler.hasClass(event.target, 'p-column-resizer')) if (event.target.nodeName === 'INPUT' || event.target.nodeName === 'TEXTAREA' || DomHandler.hasClass(event.target, 'p-column-resizer'))
event.currentTarget.draggable = false; event.currentTarget.draggable = false;
else else
@ -1050,7 +1058,7 @@ export default {
if (allowDrop) { if (allowDrop) {
ObjectUtils.reorderArray(this.columnOrder, dragIndex, dropIndex); ObjectUtils.reorderArray(this.columnOrder, dragIndex, dropIndex);
this.$emit('colreorder', { this.$emit('col-reorder', {
dragIndex: dragIndex, dragIndex: dragIndex,
dropIndex: dropIndex, dropIndex: dropIndex,
columns: this.columns columns: this.columns
@ -1088,6 +1096,83 @@ export default {
} }
return null; return null;
},
onRowMouseDown(event) {
if (DomHandler.hasClass(event.target, 'p-datatable-reorderablerow-handle'))
event.currentTarget.draggable = true;
else
event.currentTarget.draggable = false;
},
onRowDragStart(event, index) {
this.rowDragging = true;
this.draggedRowIndex = index;
event.dataTransfer.setData('text', 'b'); // For firefox
},
onRowDragOver(event, index) {
if (this.rowDragging && this.draggedRowIndex !== index) {
let rowElement = event.currentTarget;
let rowY = DomHandler.getOffset(rowElement).top + DomHandler.getWindowScrollTop();
let pageY = event.pageY;
let rowMidY = rowY + DomHandler.getOuterHeight(rowElement) / 2;
let prevRowElement = rowElement.previousElementSibling;
if (pageY < rowMidY) {
DomHandler.removeClass(rowElement, 'p-datatable-dragpoint-bottom');
this.droppedRowIndex = index;
if (prevRowElement)
DomHandler.addClass(prevRowElement, 'p-datatable-dragpoint-bottom');
else
DomHandler.addClass(rowElement, 'p-datatable-dragpoint-top');
}
else {
if (prevRowElement)
DomHandler.removeClass(prevRowElement, 'p-datatable-dragpoint-bottom');
else
DomHandler.addClass(rowElement, 'p-datatable-dragpoint-top');
this.droppedRowIndex = index + 1;
DomHandler.addClass(rowElement, 'p-datatable-dragpoint-bottom');
}
event.preventDefault();
}
},
onRowDragLeave(event) {
let rowElement = event.currentTarget;
let prevRowElement = rowElement.previousElementSibling;
if (prevRowElement) {
DomHandler.removeClass(prevRowElement, 'p-datatable-dragpoint-bottom');
}
DomHandler.removeClass(rowElement, 'p-datatable-dragpoint-bottom');
DomHandler.removeClass(rowElement, 'p-datatable-dragpoint-top');
},
onRowDragEnd(event) {
this.rowDragging = false;
this.draggedRowIndex = null;
this.droppedRowIndex = null;
event.currentTarget.draggable = false;
},
onRowDrop(event) {
let rowElement = event.currentTarget;
if (this.droppedRowIndex != null) {
let dropIndex = (this.draggedRowIndex > this.droppedRowIndex) ? this.droppedRowIndex : (this.droppedRowIndex === 0) ? 0 : this.droppedRowIndex - 1;
let processedData = [...this.processedData];
ObjectUtils.reorderArray(processedData, this.draggedRowIndex, dropIndex);
this.$emit('row-reorder', {
dragIndex: this.draggedRowIndex,
dropIndex: dropIndex,
value: processedData
});
}
//cleanup
this.onRowDragLeave(event);
this.onRowDragEnd(event);
event.preventDefault();
} }
}, },
computed: { computed: {

View File

@ -10,7 +10,8 @@
</div> </div>
<div class="content-section implementation"> <div class="content-section implementation">
<DataTable :value="cars" :reorderableColumns="true" @colreorder="onColReorder"> <DataTable :value="cars" :reorderableColumns="true" @col-reorder="onColReorder" @row-reorder="onRowReorder">
<Column :rowReorder="true" headerStyle="width: 3em" :reorderableColumn="false" />
<Column v-for="col of columns" :field="col.field" :header="col.header" :key="col.field"></Column> <Column v-for="col of columns" :field="col.field" :header="col.header" :key="col.field"></Column>
</DataTable> </DataTable>
</div> </div>
@ -20,12 +21,47 @@
<TabPanel header="Source"> <TabPanel header="Source">
<CodeHighlight> <CodeHighlight>
<template v-pre> <template v-pre>
&lt;DataTable :value="cars" :reorderableColumns="true" @col-reorder="onColReorder" @row-reorder="onRowReorder"&gt;
&lt;Column :rowReorder="true" headerStyle="width: 3em" :reorderableColumn="false" /&gt;
&lt;Column v-for="col of columns" :field="col.field" :header="col.header" :key="col.field"&gt;&lt;/Column&gt;
&lt;/DataTable&gt;
</template> </template>
</CodeHighlight> </CodeHighlight>
<CodeHighlight lang="javascript"> <CodeHighlight lang="javascript">
import CarService from '../../service/CarService';
export default {
data() {
return {
columns: null,
cars: null
}
},
carService: null,
created() {
this.carService = new CarService();
this.columns = [
{field: 'vin', header: 'Vin'},
{field: 'year', header: 'Year'},
{field: 'brand', header: 'Brand'},
{field: 'color', header: 'Color'}
];
},
mounted() {
this.carService.getCarsSmall().then(data => this.cars = data);
},
methods: {
onColReorder(event) {
this.$toast.add({severity:'success', summary: 'Column Reordered', life: 3000});
},
onRowReorder(event) {
this.cars = event.value;
this.$toast.add({severity:'success', summary: 'Rows Reordered', life: 3000});
}
}
}
</CodeHighlight> </CodeHighlight>
</TabPanel> </TabPanel>
</TabView> </TabView>
@ -62,6 +98,10 @@ export default {
methods: { methods: {
onColReorder(event) { onColReorder(event) {
this.$toast.add({severity:'success', summary: 'Column Reordered', life: 3000}); this.$toast.add({severity:'success', summary: 'Column Reordered', life: 3000});
},
onRowReorder(event) {
this.cars = event.value;
this.$toast.add({severity:'success', summary: 'Rows Reordered', life: 3000});
} }
}, },
components: { components: {