Fixed #30 - Resizable Columns for DataTable
parent
8392145dee
commit
6049081220
|
@ -32,11 +32,14 @@ export declare class DataTable extends Vue {
|
||||||
csvSeparator?: string;
|
csvSeparator?: string;
|
||||||
exportFilename?: string;
|
exportFilename?: string;
|
||||||
autoLayout?: boolean;
|
autoLayout?: boolean;
|
||||||
|
resizableColumns?: boolean;
|
||||||
|
columnResizeMode?: string;
|
||||||
$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: 'row-select', event: Event): this;
|
$emit(eventName: 'row-select', event: Event): this;
|
||||||
$emit(eventName: 'row-unselect', event: Event): this;
|
$emit(eventName: 'row-unselect', event: Event): this;
|
||||||
|
$emit(eventName: 'column-resize-end', event: Event): this;
|
||||||
$slots: {
|
$slots: {
|
||||||
header: VNode[];
|
header: VNode[];
|
||||||
paginatorLeft: VNode[];
|
paginatorLeft: VNode[];
|
||||||
|
|
|
@ -20,10 +20,11 @@
|
||||||
<slot name="paginatorRight"></slot>
|
<slot name="paginatorRight"></slot>
|
||||||
</template>
|
</template>
|
||||||
</DTPaginator>
|
</DTPaginator>
|
||||||
<table>
|
<table ref="table">
|
||||||
<thead class="p-datatable-thead">
|
<thead class="p-datatable-thead">
|
||||||
<tr>
|
<tr>
|
||||||
<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)">
|
||||||
|
<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" />
|
||||||
<span class="p-column-title" v-if="col.header">{{col.header}}</span>
|
<span class="p-column-title" v-if="col.header">{{col.header}}</span>
|
||||||
<span v-if="col.sortable" :class="getSortableColumnIcon(col)"></span>
|
<span v-if="col.sortable" :class="getSortableColumnIcon(col)"></span>
|
||||||
|
@ -74,6 +75,7 @@
|
||||||
<slot name="footer"></slot>
|
<slot name="footer"></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div ref="resizeHelper" class="p-column-resizer-helper p-highlight" style="display: none"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -228,6 +230,14 @@ export default {
|
||||||
autoLayout: {
|
autoLayout: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
},
|
||||||
|
resizableColumns: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
columnResizeMode: {
|
||||||
|
type: String,
|
||||||
|
default: 'fit'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -244,6 +254,10 @@ export default {
|
||||||
rowTouched: false,
|
rowTouched: false,
|
||||||
anchorRowIndex: null,
|
anchorRowIndex: null,
|
||||||
rangeRowIndex: null,
|
rangeRowIndex: null,
|
||||||
|
documentColumnResizeListener: null,
|
||||||
|
documentColumnResizeEndListener: null,
|
||||||
|
lastResizeHelperX: null,
|
||||||
|
resizeColumnElement: null,
|
||||||
watch: {
|
watch: {
|
||||||
first(newValue) {
|
first(newValue) {
|
||||||
this.d_first = newValue;
|
this.d_first = newValue;
|
||||||
|
@ -269,6 +283,9 @@ export default {
|
||||||
mounted() {
|
mounted() {
|
||||||
this.allChildren = this.$children;
|
this.allChildren = this.$children;
|
||||||
},
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.unbindColumnResizeEvents();
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
resolveFieldData(rowData, field) {
|
resolveFieldData(rowData, field) {
|
||||||
return ObjectUtils.resolveFieldData(rowData, field);
|
return ObjectUtils.resolveFieldData(rowData, field);
|
||||||
|
@ -388,6 +405,7 @@ export default {
|
||||||
|
|
||||||
return [column.headerClass,
|
return [column.headerClass,
|
||||||
{'p-sortable-column': column.sortable},
|
{'p-sortable-column': column.sortable},
|
||||||
|
{'p-resizable-column': this.resizableColumns},
|
||||||
{'p-highlight': sorted}
|
{'p-highlight': sorted}
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
@ -834,6 +852,88 @@ export default {
|
||||||
resetPage() {
|
resetPage() {
|
||||||
this.d_first = 0;
|
this.d_first = 0;
|
||||||
this.$emit('update:first', this.d_first);
|
this.$emit('update:first', this.d_first);
|
||||||
|
},
|
||||||
|
onColumnResizeStart(event) {
|
||||||
|
let containerLeft = DomHandler.getOffset(this.$el).left;
|
||||||
|
this.resizeColumnElement = event.target.parentElement;
|
||||||
|
this.columnResizing = true;
|
||||||
|
this.lastResizeHelperX = (event.pageX - containerLeft + this.$el.scrollLeft);
|
||||||
|
|
||||||
|
this.bindColumnResizeEvents();
|
||||||
|
},
|
||||||
|
onColumnResize(event) {
|
||||||
|
let containerLeft = DomHandler.getOffset(this.$el).left;
|
||||||
|
DomHandler.addClass(this.$el, 'p-unselectable-text');
|
||||||
|
this.$refs.resizeHelper.style.height = this.$el.offsetHeight + 'px';
|
||||||
|
this.$refs.resizeHelper.style.top = 0 + 'px';
|
||||||
|
this.$refs.resizeHelper.style.left = (event.pageX - containerLeft + this.$el.scrollLeft) + 'px';
|
||||||
|
|
||||||
|
this.$refs.resizeHelper.style.display = 'block';
|
||||||
|
},
|
||||||
|
onColumnResizeEnd(event) {
|
||||||
|
let delta = this.$refs.resizeHelper.offsetLeft - this.lastResizeHelperX;
|
||||||
|
let columnWidth = this.resizeColumnElement.offsetWidth;
|
||||||
|
let newColumnWidth = columnWidth + delta;
|
||||||
|
let minWidth = this.resizeColumnElement.style.minWidth||15;
|
||||||
|
|
||||||
|
if(columnWidth + delta > parseInt(minWidth, 10)) {
|
||||||
|
if(this.columnResizeMode === 'fit') {
|
||||||
|
let nextColumn = this.resizeColumnElement.nextElementSibling;
|
||||||
|
let nextColumnWidth = nextColumn.offsetWidth - delta;
|
||||||
|
|
||||||
|
if(newColumnWidth > 15 && nextColumnWidth > 15) {
|
||||||
|
this.resizeColumnElement.style.width = newColumnWidth + 'px';
|
||||||
|
if(nextColumn) {
|
||||||
|
nextColumn.style.width = nextColumnWidth + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(this.columnResizeMode === 'expand') {
|
||||||
|
this.$refs.table.style.width = this.$refs.table.offsetWidth + delta + 'px';
|
||||||
|
this.resizeColumnElement.style.width = newColumnWidth + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$emit('column-resize-end', {
|
||||||
|
element: this.resizeColumnElement,
|
||||||
|
delta: delta
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$refs.resizeHelper.style.display = 'none';
|
||||||
|
this.resizeColumn = null;
|
||||||
|
DomHandler.removeClass(this.$el, 'p-unselectable-text');
|
||||||
|
|
||||||
|
this.unbindColumnResizeEvents();
|
||||||
|
},
|
||||||
|
bindColumnResizeEvents() {
|
||||||
|
if (!this.documentColumnResizeListener) {
|
||||||
|
this.documentColumnResizeListener = document.addEventListener('mousemove', (event) => {
|
||||||
|
if(this.columnResizing) {
|
||||||
|
this.onColumnResize(event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.documentColumnResizeEndListener) {
|
||||||
|
this.documentColumnResizeEndListener = document.addEventListener('mouseup', (event) => {
|
||||||
|
if(this.columnResizing) {
|
||||||
|
this.columnResizing = false;
|
||||||
|
this.onColumnResizeEnd(event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
unbindColumnResizeEvents() {
|
||||||
|
if (this.documentColumnResizeListener) {
|
||||||
|
document.removeEventListener('document', this.documentColumnResizeListener);
|
||||||
|
this.documentColumnResizeListener = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.documentColumnResizeEndListener) {
|
||||||
|
document.removeEventListener('document', this.documentColumnResizeEndListener);
|
||||||
|
this.documentColumnResizeEndListener = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -841,7 +941,9 @@ export default {
|
||||||
return [
|
return [
|
||||||
'p-datatable p-component', {
|
'p-datatable p-component', {
|
||||||
'p-datatable-hoverable-rows': (this.rowHover || this.selectionMode),
|
'p-datatable-hoverable-rows': (this.rowHover || this.selectionMode),
|
||||||
'p-datatable-auto-layout': this.autoLayout
|
'p-datatable-auto-layout': this.autoLayout,
|
||||||
|
'p-datatable-resizable': this.resizableColumns,
|
||||||
|
'p-datatable-resizable-fit': this.resizableColumns && this.columnResizeMode === 'fit',
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
|
@ -156,6 +156,11 @@ export default new Router({
|
||||||
name: 'datatableexport',
|
name: 'datatableexport',
|
||||||
component: () => import('./views/datatable/DataTableExportDemo.vue')
|
component: () => import('./views/datatable/DataTableExportDemo.vue')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/datatable/colresize',
|
||||||
|
name: 'datatablecolresize',
|
||||||
|
component: () => import('./views/datatable/DataTableColResizeDemo.vue')
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/datatable/crud',
|
path: '/datatable/crud',
|
||||||
name: 'datatablecrud',
|
name: 'datatablecrud',
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<DataTableSubMenu />
|
||||||
|
|
||||||
|
<div class="content-section introduction">
|
||||||
|
<div class="feature-intro">
|
||||||
|
<h1>DataTable - Column Resize</h1>
|
||||||
|
<p>Columns can be resized using drag drop by setting the resizableColumns to true. There are two resize modes; "fit" and "expand". Fit is the default one and the overall table width does not change when a column is resized.
|
||||||
|
In "expand" mode, table width also changes along with the column width. onColumnResize is a callback that passes the resized column header as a parameter.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content-section implementation">
|
||||||
|
<h3>Fit Mode</h3>
|
||||||
|
<DataTable :value="cars" :resizableColumns="true" columnResizeMode="fit">
|
||||||
|
<Column field="vin" header="Vin" :resizable="true"></Column>
|
||||||
|
<Column field="year" header="Year" :resizable="true"></Column>
|
||||||
|
<Column field="brand" header="Brand" :resizable="true"></Column>
|
||||||
|
<Column field="color" header="Color" :resizable="true"></Column>
|
||||||
|
</DataTable>
|
||||||
|
|
||||||
|
<h3>Expand Mode</h3>
|
||||||
|
<DataTable :value="cars" :resizableColumns="true" columnResizeMode="expand">
|
||||||
|
<Column field="vin" header="Vin" :resizable="true"></Column>
|
||||||
|
<Column field="year" header="Year" :resizable="true"></Column>
|
||||||
|
<Column field="brand" header="Brand" :resizable="true"></Column>
|
||||||
|
<Column field="color" header="Color" :resizable="true"></Column>
|
||||||
|
</DataTable>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content-section documentation">
|
||||||
|
<TabView>
|
||||||
|
<TabPanel header="Source">
|
||||||
|
<CodeHighlight>
|
||||||
|
<template v-pre>
|
||||||
|
<h3>Fit Mode</h3>
|
||||||
|
<DataTable :value="cars" :resizableColumns="true" columnResizeMode="fit">
|
||||||
|
<Column field="vin" header="Vin" :resizable="true"></Column>
|
||||||
|
<Column field="year" header="Year" :resizable="true"></Column>
|
||||||
|
<Column field="brand" header="Brand" :resizable="true"></Column>
|
||||||
|
<Column field="color" header="Color" :resizable="true"></Column>
|
||||||
|
</DataTable>
|
||||||
|
|
||||||
|
<h3>Expand Mode</h3>
|
||||||
|
<DataTable :value="cars" :resizableColumns="true" columnResizeMode="expand">
|
||||||
|
<Column field="vin" header="Vin" :resizable="true"></Column>
|
||||||
|
<Column field="year" header="Year" :resizable="true"></Column>
|
||||||
|
<Column field="brand" header="Brand" :resizable="true"></Column>
|
||||||
|
<Column field="color" header="Color" :resizable="true"></Column>
|
||||||
|
</DataTable>
|
||||||
|
</template>
|
||||||
|
</CodeHighlight>
|
||||||
|
|
||||||
|
<CodeHighlight lang="javascript">
|
||||||
|
import CarService from '../../service/CarService';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
cars: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
carService: null,
|
||||||
|
created() {
|
||||||
|
this.carService = new CarService();
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.carService.getCarsSmall().then(data => this.cars = data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</CodeHighlight>
|
||||||
|
</TabPanel>
|
||||||
|
</TabView>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import CarService from '../../service/CarService';
|
||||||
|
import DataTableSubMenu from './DataTableSubMenu';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
cars: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
carService: null,
|
||||||
|
created() {
|
||||||
|
this.carService = new CarService();
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.carService.getCarsSmall().then(data => this.cars = data);
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
'DataTableSubMenu': DataTableSubMenu
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -532,6 +532,34 @@ data() {
|
||||||
<Column field="color" header="Color"></Column>
|
<Column field="color" header="Color"></Column>
|
||||||
</DataTable>
|
</DataTable>
|
||||||
</template>
|
</template>
|
||||||
|
</CodeHighlight>
|
||||||
|
|
||||||
|
<h3>Column Resize</h3>
|
||||||
|
<p>Columns can be resized using drag drop by setting the <i>resizableColumns</i> to true. There are two resize modes; "fit" and "expand". Fit is the default one and the overall table width does not change when a column is resized.
|
||||||
|
In "expand" mode, table width also changes along with the column width. <i>column-resize-end</i> is a callback that passes the resized column header and delta change as a parameter.</p>
|
||||||
|
<CodeHighlight>
|
||||||
|
<template v-pre>
|
||||||
|
<DataTable :value="cars" :resizableColumns="true" columnResizeMode="fit | expand">
|
||||||
|
<Column field="vin" header="Vin" :resizable="true"></Column>
|
||||||
|
<Column field="year" header="Year" :resizable="true"></Column>
|
||||||
|
<Column field="brand" header="Brand" :resizable="true"></Column>
|
||||||
|
<Column field="color" header="Color" :resizable="true"></Column>
|
||||||
|
</DataTable>
|
||||||
|
</template>
|
||||||
|
</CodeHighlight>
|
||||||
|
</CodeHighlight>
|
||||||
|
|
||||||
|
<p>It is important to note that when you need to change column widths, since table width is 100%, giving fixed pixel widths does not work well as browsers scale them, instead give percentage widths.</p>
|
||||||
|
<CodeHighlight>
|
||||||
|
<template v-pre>
|
||||||
|
<DataTable :value="cars" :resizableColumns="true" columnResizeMode="fit | expand">
|
||||||
|
<Column field="vin" header="Vin" :resizable="true" headerStyle="width: 20%"></Column>
|
||||||
|
<Column field="year" header="Year" :resizable="true" headerStyle="width: 40%"></Column>
|
||||||
|
<Column field="brand" header="Brand" :resizable="true" headerStyle="width: 20%"></Column>
|
||||||
|
<Column field="color" header="Color" :resizable="true" headerStyle="width: 20%"></Column>
|
||||||
|
</DataTable>
|
||||||
|
</template>
|
||||||
|
</CodeHighlight>
|
||||||
</CodeHighlight>
|
</CodeHighlight>
|
||||||
|
|
||||||
<h3>Data Export</h3>
|
<h3>Data Export</h3>
|
||||||
|
@ -918,6 +946,18 @@ export default {
|
||||||
<td>false</td>
|
<td>false</td>
|
||||||
<td>Whether the cell widths scale according to their content or not.</td>
|
<td>Whether the cell widths scale according to their content or not.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>resizableColumns</td>
|
||||||
|
<td>boolean</td>
|
||||||
|
<td>false</td>
|
||||||
|
<td>When enabled, columns can be resized using drag and drop.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>columnResizeMode</td>
|
||||||
|
<td>string</td>
|
||||||
|
<td>fit</td>
|
||||||
|
<td>Defines whether the overall table width should change on column resize, <br/> valid values are "fit" and "expand".</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
@ -970,6 +1010,12 @@ export default {
|
||||||
event.type: Type of the selection, valid values are "row", "radio" or "checkbox".</td>
|
event.type: Type of the selection, valid values are "row", "radio" or "checkbox".</td>
|
||||||
<td>Callback to invoke when a row is unselected.</td>
|
<td>Callback to invoke when a row is unselected.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>column-resize-end</td>
|
||||||
|
<td>event.element: DOM element of the resized column.<br />
|
||||||
|
event.delta: Change in column width</td>
|
||||||
|
<td>Callback to invoke when a column is resized.</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
<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/export">● Export</router-link></li>
|
||||||
|
<li><router-link to="/datatable/colresize">● ColResize</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>
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import NodeService from '../../service/NodeService';
|
import NodeService from '../../service/NodeService';
|
||||||
import TreeTableDoc from './TreeTableDoc';
|
|
||||||
import TreeTableSubMenu from './TreeTableSubMenu';
|
import TreeTableSubMenu from './TreeTableSubMenu';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -47,7 +46,6 @@ export default {
|
||||||
this.nodeService.getTreeTableNodes().then(data => this.nodes = data);
|
this.nodeService.getTreeTableNodes().then(data => this.nodes = data);
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
'TreeTableDoc': TreeTableDoc,
|
|
||||||
'TreeTableSubMenu': TreeTableSubMenu
|
'TreeTableSubMenu': TreeTableSubMenu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue