Implemented Column Reorder
parent
c5d097bad6
commit
3e9d598dba
|
@ -23,7 +23,9 @@
|
||||||
<table ref="table">
|
<table ref="table">
|
||||||
<thead class="p-datatable-thead">
|
<thead class="p-datatable-thead">
|
||||||
<tr v-if="!headerColumnGroup">
|
<tr v-if="!headerColumnGroup">
|
||||||
<th v-for="(col,i) of columns" :key="col.columnKey||col.field||i" :style="col.headerStyle" :class="getColumnHeaderClass(col)" @click="onColumnHeaderClick($event, col)"
|
<th v-for="(col,i) of columns" :key="col.columnKey||col.field||i" :style="col.headerStyle" :class="getColumnHeaderClass(col)"
|
||||||
|
@click="onColumnHeaderClick($event, col)" @mousedown="onColumnHeaderMouseDown($event, 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">
|
||||||
<span class="p-column-resizer p-clickable" @mousedown="onColumnResizeStart" v-if="resizableColumns"></span>
|
<span class="p-column-resizer p-clickable" @mousedown="onColumnResizeStart" v-if="resizableColumns"></span>
|
||||||
<ColumnSlot :column="col" type="header" v-if="col.$scopedSlots.header" />
|
<ColumnSlot :column="col" type="header" v-if="col.$scopedSlots.header" />
|
||||||
|
@ -99,6 +101,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div ref="resizeHelper" class="p-column-resizer-helper p-highlight" style="display: none"></div>
|
<div ref="resizeHelper" class="p-column-resizer-helper p-highlight" style="display: none"></div>
|
||||||
|
<span ref="reorderIndicatorUp" class="pi pi-arrow-down p-datatable-reorder-indicator-up" style="position: absolute; display: none" v-if="reorderableColumns" />
|
||||||
|
<span ref="reorderIndicatorDown" class="pi pi-arrow-up p-datatable-reorder-indicator-down" style="position: absolute; display: none" v-if="reorderableColumns" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -261,6 +265,10 @@ export default {
|
||||||
columnResizeMode: {
|
columnResizeMode: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'fit'
|
default: 'fit'
|
||||||
|
},
|
||||||
|
reorderableColumns: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -271,7 +279,8 @@ export default {
|
||||||
d_sortField: this.sortField,
|
d_sortField: this.sortField,
|
||||||
d_sortOrder: this.sortOrder,
|
d_sortOrder: this.sortOrder,
|
||||||
d_multiSortMeta: this.multiSortMeta ? [...this.multiSortMeta] : [],
|
d_multiSortMeta: this.multiSortMeta ? [...this.multiSortMeta] : [],
|
||||||
d_selectionKeys: null
|
d_selectionKeys: null,
|
||||||
|
columnOrder: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
rowTouched: false,
|
rowTouched: false,
|
||||||
|
@ -281,6 +290,10 @@ export default {
|
||||||
documentColumnResizeEndListener: null,
|
documentColumnResizeEndListener: null,
|
||||||
lastResizeHelperX: null,
|
lastResizeHelperX: null,
|
||||||
resizeColumnElement: null,
|
resizeColumnElement: null,
|
||||||
|
columnResizing: false,
|
||||||
|
colReorderIconWidth: null,
|
||||||
|
colReorderIconHeight: null,
|
||||||
|
draggedColumn: null,
|
||||||
watch: {
|
watch: {
|
||||||
first(newValue) {
|
first(newValue) {
|
||||||
this.d_first = newValue;
|
this.d_first = newValue;
|
||||||
|
@ -305,6 +318,16 @@ export default {
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.allChildren = this.$children;
|
this.allChildren = this.$children;
|
||||||
|
|
||||||
|
if (this.reorderableColumns) {
|
||||||
|
let columnOrder = [];
|
||||||
|
for (let child of this.allChildren) {
|
||||||
|
if (child.$options._propKeys.indexOf('columnKey') !== -1) {
|
||||||
|
columnOrder.push(child.columnKey||child.field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.columnOrder = columnOrder;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.unbindColumnResizeEvents();
|
this.unbindColumnResizeEvents();
|
||||||
|
@ -956,6 +979,115 @@ export default {
|
||||||
document.removeEventListener('document', this.documentColumnResizeEndListener);
|
document.removeEventListener('document', this.documentColumnResizeEndListener);
|
||||||
this.documentColumnResizeEndListener = null;
|
this.documentColumnResizeEndListener = null;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
onColumnHeaderMouseDown(event) {
|
||||||
|
if (this.reorderableColumns) {
|
||||||
|
if (event.target.nodeName === 'INPUT' || event.target.nodeName === 'TEXTAREA' || DomHandler.hasClass(event.target, 'p-column-resizer'))
|
||||||
|
event.currentTarget.draggable = false;
|
||||||
|
else
|
||||||
|
event.currentTarget.draggable = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onColumnHeaderDragStart(event) {
|
||||||
|
if(this.columnResizing) {
|
||||||
|
event.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.colReorderIconWidth = DomHandler.getHiddenElementOuterWidth(this.$refs.reorderIndicatorUp);
|
||||||
|
this.colReorderIconHeight = DomHandler.getHiddenElementOuterHeight(this.$refs.reorderIndicatorUp);
|
||||||
|
|
||||||
|
this.draggedColumn = this.findParentHeader(event.target);
|
||||||
|
event.dataTransfer.setData('text', 'b'); // Firefox requires this to make dragging possible
|
||||||
|
},
|
||||||
|
onColumnHeaderDragOver(event) {
|
||||||
|
let dropHeader = this.findParentHeader(event.target);
|
||||||
|
if(this.reorderableColumns && this.draggedColumn && dropHeader) {
|
||||||
|
event.preventDefault();
|
||||||
|
let containerOffset = DomHandler.getOffset(this.$el);
|
||||||
|
let dropHeaderOffset = DomHandler.getOffset(dropHeader);
|
||||||
|
|
||||||
|
if (this.draggedColumn !== dropHeader) {
|
||||||
|
let targetLeft = dropHeaderOffset.left - containerOffset.left;
|
||||||
|
let columnCenter = dropHeaderOffset.left + dropHeader.offsetWidth / 2;
|
||||||
|
|
||||||
|
this.$refs.reorderIndicatorUp.style.top = dropHeaderOffset.top - containerOffset.top - (this.colReorderIconHeight - 1) + 'px';
|
||||||
|
this.$refs.reorderIndicatorDown.style.top = dropHeaderOffset.top - containerOffset.top + dropHeader.offsetHeight + 'px';
|
||||||
|
|
||||||
|
if(event.pageX > columnCenter) {
|
||||||
|
this.$refs.reorderIndicatorUp.style.left = (targetLeft + dropHeader.offsetWidth - Math.ceil(this.colReorderIconWidth / 2)) + 'px';
|
||||||
|
this.$refs.reorderIndicatorDown.style.left = (targetLeft + dropHeader.offsetWidth - Math.ceil(this.colReorderIconWidth / 2))+ 'px';
|
||||||
|
this.dropPosition = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.$refs.reorderIndicatorUp.style.left = (targetLeft - Math.ceil(this.colReorderIconWidth / 2)) + 'px';
|
||||||
|
this.$refs.reorderIndicatorDown.style.left = (targetLeft - Math.ceil(this.colReorderIconWidth / 2))+ 'px';
|
||||||
|
this.dropPosition = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$refs.reorderIndicatorUp.style.display = 'block';
|
||||||
|
this.$refs.reorderIndicatorDown.style.display = 'block';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onColumnHeaderDragLeave(event) {
|
||||||
|
if(this.reorderableColumns && this.draggedColumn) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.$refs.reorderIndicatorUp.style.display = 'none';
|
||||||
|
this.$refs.reorderIndicatorDown.style.display = 'none';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onColumnHeaderDrop(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
if (this.draggedColumn) {
|
||||||
|
let dragIndex = DomHandler.index(this.draggedColumn);
|
||||||
|
let dropIndex = DomHandler.index(this.findParentHeader(event.target));
|
||||||
|
let allowDrop = (dragIndex !== dropIndex);
|
||||||
|
if (allowDrop && ((dropIndex - dragIndex === 1 && this.dropPosition === -1) || (dragIndex - dropIndex === 1 && this.dropPosition === 1))) {
|
||||||
|
allowDrop = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allowDrop) {
|
||||||
|
ObjectUtils.reorderArray(this.columnOrder, dragIndex, dropIndex);
|
||||||
|
|
||||||
|
this.$emit('colreorder', {
|
||||||
|
dragIndex: dragIndex,
|
||||||
|
dropIndex: dropIndex,
|
||||||
|
columns: this.columns
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$refs.reorderIndicatorUp.style.display = 'none';
|
||||||
|
this.$refs.reorderIndicatorDown.style.display = 'none';
|
||||||
|
this.draggedColumn.draggable = false;
|
||||||
|
this.draggedColumn = null;
|
||||||
|
this.dropPosition = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
findParentHeader(element) {
|
||||||
|
if(element.nodeName === 'TH') {
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let parent = element.parentElement;
|
||||||
|
while(parent.nodeName !== 'TH') {
|
||||||
|
parent = parent.parentElement;
|
||||||
|
if (!parent) break;
|
||||||
|
}
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
findColumnByKey(columns, key) {
|
||||||
|
if(columns && columns.length) {
|
||||||
|
for(let i = 0; i < columns.length; i++) {
|
||||||
|
let child = columns[i];
|
||||||
|
if(child.columnKey === key || child.field === key) {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -970,10 +1102,27 @@ export default {
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
columns() {
|
columns() {
|
||||||
|
let columns = [];
|
||||||
|
|
||||||
if (this.allChildren) {
|
if (this.allChildren) {
|
||||||
return this.allChildren.filter(child => child.$options._propKeys.indexOf('columnKey') !== -1);
|
columns = this.allChildren.filter(child => child.$options._propKeys.indexOf('columnKey') !== -1);
|
||||||
|
|
||||||
|
if (this.reorderableColumns && this.columnOrder) {
|
||||||
|
let orderedColumns = [];
|
||||||
|
for (let columnKey of this.columnOrder) {
|
||||||
|
let column = this.findColumnByKey(columns, columnKey);
|
||||||
|
if (column) {
|
||||||
|
orderedColumns.push(column);
|
||||||
}
|
}
|
||||||
return [];
|
}
|
||||||
|
|
||||||
|
return [...orderedColumns, ...columns.filter((item) => {
|
||||||
|
return orderedColumns.indexOf(item) < 0;
|
||||||
|
})];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return columns;
|
||||||
},
|
},
|
||||||
headerColumnGroup() {
|
headerColumnGroup() {
|
||||||
if (this.allChildren) {
|
if (this.allChildren) {
|
||||||
|
|
|
@ -146,6 +146,11 @@ export default new Router({
|
||||||
name: 'datatablecoltoggle',
|
name: 'datatablecoltoggle',
|
||||||
component: () => import('./views/datatable/DataTableColToggleDemo.vue')
|
component: () => import('./views/datatable/DataTableColToggleDemo.vue')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/datatable/reorder',
|
||||||
|
name: 'datatablereorder',
|
||||||
|
component: () => import('./views/datatable/DataTableReorderDemo.vue')
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/datatable/responsive',
|
path: '/datatable/responsive',
|
||||||
name: 'datatableresponsive',
|
name: 'datatableresponsive',
|
||||||
|
|
|
@ -60,7 +60,3 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
|
|
||||||
</style>
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<DataTableSubMenu />
|
||||||
|
|
||||||
|
<div class="content-section introduction">
|
||||||
|
<div class="feature-intro">
|
||||||
|
<h1>DataTable - Reorder</h1>
|
||||||
|
<p>Order of the columns and rows can be changed using drag and drop.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content-section implementation">
|
||||||
|
<DataTable :value="cars" :reorderableColumns="true" @colreorder="onColReorder">
|
||||||
|
<Column v-for="col of columns" :field="col.field" :header="col.header" :key="col.field"></Column>
|
||||||
|
</DataTable>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content-section documentation">
|
||||||
|
<TabView>
|
||||||
|
<TabPanel header="Source">
|
||||||
|
<CodeHighlight>
|
||||||
|
<template v-pre>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
</CodeHighlight>
|
||||||
|
|
||||||
|
<CodeHighlight lang="javascript">
|
||||||
|
|
||||||
|
</CodeHighlight>
|
||||||
|
</TabPanel>
|
||||||
|
</TabView>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import CarService from '../../service/CarService';
|
||||||
|
import DataTableSubMenu from './DataTableSubMenu';
|
||||||
|
import DataTableDoc from './DataTableDoc';
|
||||||
|
|
||||||
|
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});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
'DataTableDoc': DataTableDoc,
|
||||||
|
'DataTableSubMenu': DataTableSubMenu
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -11,8 +11,9 @@
|
||||||
<li><router-link to="/datatable/colgroup">● ColGroup</router-link></li>
|
<li><router-link to="/datatable/colgroup">● ColGroup</router-link></li>
|
||||||
<li><router-link to="/datatable/coltoggle">● ColToggle</router-link></li>
|
<li><router-link to="/datatable/coltoggle">● ColToggle</router-link></li>
|
||||||
<li><router-link to="/datatable/responsive">● Responsive</router-link></li>
|
<li><router-link to="/datatable/responsive">● Responsive</router-link></li>
|
||||||
<li><router-link to="/datatable/export">● Export</router-link></li>
|
<li><router-link to="/datatable/reorder">● Reorder</router-link></li>
|
||||||
<li><router-link to="/datatable/colresize">● ColResize</router-link></li>
|
<li><router-link to="/datatable/colresize">● ColResize</router-link></li>
|
||||||
|
<li><router-link to="/datatable/export">● Export</router-link></li>
|
||||||
<li><router-link to="/datatable/crud">● Crud</router-link></li>
|
<li><router-link to="/datatable/crud">● Crud</router-link></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue