diff --git a/src/components/datatable/DataTable.d.ts b/src/components/datatable/DataTable.d.ts index 0651560a7..6920c7d3d 100644 --- a/src/components/datatable/DataTable.d.ts +++ b/src/components/datatable/DataTable.d.ts @@ -32,11 +32,14 @@ export declare class DataTable extends Vue { csvSeparator?: string; exportFilename?: string; autoLayout?: boolean; + resizableColumns?: boolean; + columnResizeMode?: string; $emit(eventName: 'page', event: Event): this; $emit(eventName: 'sort', event: Event): this; $emit(eventName: 'filter', event: Event): this; $emit(eventName: 'row-select', event: Event): this; $emit(eventName: 'row-unselect', event: Event): this; + $emit(eventName: 'column-resize-end', event: Event): this; $slots: { header: VNode[]; paginatorLeft: VNode[]; diff --git a/src/components/datatable/DataTable.vue b/src/components/datatable/DataTable.vue index 2b6a89d2a..62d79c235 100644 --- a/src/components/datatable/DataTable.vue +++ b/src/components/datatable/DataTable.vue @@ -20,10 +20,11 @@ - +
+ + + + + + + + + + + +
+ {{col.header}} @@ -74,6 +75,7 @@ + @@ -228,6 +230,14 @@ export default { autoLayout: { type: Boolean, default: false + }, + resizableColumns: { + type: Boolean, + default: false + }, + columnResizeMode: { + type: String, + default: 'fit' } }, data() { @@ -244,6 +254,10 @@ export default { rowTouched: false, anchorRowIndex: null, rangeRowIndex: null, + documentColumnResizeListener: null, + documentColumnResizeEndListener: null, + lastResizeHelperX: null, + resizeColumnElement: null, watch: { first(newValue) { this.d_first = newValue; @@ -269,6 +283,9 @@ export default { mounted() { this.allChildren = this.$children; }, + beforeDestroy() { + this.unbindColumnResizeEvents(); + }, methods: { resolveFieldData(rowData, field) { return ObjectUtils.resolveFieldData(rowData, field); @@ -388,6 +405,7 @@ export default { return [column.headerClass, {'p-sortable-column': column.sortable}, + {'p-resizable-column': this.resizableColumns}, {'p-highlight': sorted} ]; }, @@ -834,6 +852,88 @@ export default { resetPage() { this.d_first = 0; 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: { @@ -841,7 +941,9 @@ export default { return [ 'p-datatable p-component', { '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', } ]; }, diff --git a/src/router.js b/src/router.js index bbdc5189f..a79a24b00 100644 --- a/src/router.js +++ b/src/router.js @@ -156,6 +156,11 @@ export default new Router({ name: 'datatableexport', component: () => import('./views/datatable/DataTableExportDemo.vue') }, + { + path: '/datatable/colresize', + name: 'datatablecolresize', + component: () => import('./views/datatable/DataTableColResizeDemo.vue') + }, { path: '/datatable/crud', name: 'datatablecrud', diff --git a/src/views/datatable/DataTableColResizeDemo.vue b/src/views/datatable/DataTableColResizeDemo.vue new file mode 100644 index 000000000..fec2c889f --- /dev/null +++ b/src/views/datatable/DataTableColResizeDemo.vue @@ -0,0 +1,99 @@ + + + \ No newline at end of file diff --git a/src/views/datatable/DataTableDoc.vue b/src/views/datatable/DataTableDoc.vue index e38aa425d..c36067582 100644 --- a/src/views/datatable/DataTableDoc.vue +++ b/src/views/datatable/DataTableDoc.vue @@ -532,6 +532,34 @@ data() { <Column field="color" header="Color"></Column> </DataTable> + + +

Column Resize

+

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. column-resize-end is a callback that passes the resized column header and delta change as a parameter.

+ + + + + +

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.

+ + +

Data Export

@@ -918,6 +946,18 @@ export default {
false Whether the cell widths scale according to their content or not.
resizableColumnsbooleanfalseWhen enabled, columns can be resized using drag and drop.
columnResizeModestringfitDefines whether the overall table width should change on column resize,
valid values are "fit" and "expand".
@@ -970,6 +1010,12 @@ export default { event.type: Type of the selection, valid values are "row", "radio" or "checkbox". Callback to invoke when a row is unselected. + + column-resize-end + event.element: DOM element of the resized column.
+ event.delta: Change in column width + Callback to invoke when a column is resized. + diff --git a/src/views/datatable/DataTableSubMenu.vue b/src/views/datatable/DataTableSubMenu.vue index a3b2d3b82..9b600cb54 100644 --- a/src/views/datatable/DataTableSubMenu.vue +++ b/src/views/datatable/DataTableSubMenu.vue @@ -11,6 +11,7 @@
  • ● ColToggle
  • ● Responsive
  • ● Export
  • +
  • ● ColResize
  • ● Crud
  • diff --git a/src/views/treetable/TreeTableResponsiveDemo.vue b/src/views/treetable/TreeTableResponsiveDemo.vue index 94d9342d9..f6f90fc9f 100644 --- a/src/views/treetable/TreeTableResponsiveDemo.vue +++ b/src/views/treetable/TreeTableResponsiveDemo.vue @@ -30,7 +30,6 @@