Initiated new DataTable Scrolling Implementation

pull/973/head
Cagatay Civici 2021-02-10 13:28:47 +03:00
parent 7edffc6b4d
commit 3bd70d34c1
11 changed files with 551 additions and 605 deletions

View File

@ -34,6 +34,14 @@ export default {
type: null,
default: null
},
style: {
type: null,
default: null
},
class: {
type: String,
default: null
},
headerStyle: {
type: null,
default: null

View File

@ -1,5 +1,5 @@
<template>
<td :style="columnProp('bodyStyle')" :class="containerClass" @click="onClick" @keydown="onKeyDown">
<td :style="containerStyle" :class="containerClass" @click="onClick" @keydown="onKeyDown" role="cell">
<component :is="column.children.body" :data="rowData" :column="column" :index="index" v-if="column.children && column.children.body && !d_editing" />
<component :is="column.children.editor" :data="rowData" :column="column" :index="index" v-else-if="column.children && column.children.editor && d_editing" />
<template v-else-if="columnProp('selectionMode')">
@ -73,7 +73,10 @@ export default {
selfClick: false,
data() {
return {
d_editing: this.editing
d_editing: this.editing,
styleObject: {
left: '0px'
}
}
},
watch: {
@ -82,13 +85,13 @@ export default {
}
},
mounted() {
this.children = this.$children;
if (this.columnProp('frozen')) {
this.updateStickyPosition();
}
},
updated() {
let query = this.editMode === 'row' ? '[autofocus]' : 'input';
let focusable = DomHandler.findSingle(this.$el, query);
if (focusable && document.activeElement != focusable) {
focusable.focus();
if (this.columnProp('frozen')) {
this.updateStickyPosition();
}
},
methods: {
@ -274,15 +277,33 @@ export default {
},
onRowEditCancel(event) {
this.$emit('row-edit-cancel', {originalEvent: event, data: this.rowData, field: this.columnProp('field'), index: this.index});
},
updateStickyPosition() {
if (this.columnProp('frozen')) {
let left = 0;
let prev = this.$el.previousElementSibling;
if (prev) {
left = DomHandler.getOuterWidth(prev) + parseFloat(prev.style.left);
}
this.styleObject.left = left + 'px';
}
}
},
computed: {
containerClass() {
return [this.columnProp('bodyClass'), {
return [this.columnProp('bodyClass'), this.columnProp('class'), {
'p-selection-column': this.columnProp('selectionMode') != null,
'p-editable-column': this.isEditable(),
'p-cell-editing': this.d_editing
'p-cell-editing': this.d_editing,
'p-frozen-column': this.columnProp('frozen')
}];
},
containerStyle() {
let bodyStyle = this.columnProp('bodyStyle');
let columnStyle = this.columnProp('style');
return this.columnProp('frozen') ? [columnStyle, bodyStyle, this.styleObject]: [columnStyle, bodyStyle];
}
},
components: {

View File

@ -340,14 +340,12 @@ export default {
this.selfClick = true;
},
onOverlayEnter() {
if (this.filterMenuStyle) {
DomHandler.applyStyle(this.overlay, this.filterMenuStyle);
}
document.body.appendChild(this.overlay);
this.overlay.style.zIndex = String(DomHandler.generateZIndex());
DomHandler.absolutePosition(this.overlay, this.$refs.icon);
if (this.filterMenuStyle) {
for (let prop in this.filterMenuStyle) {
this.overlay.style[prop] = this.filterMenuStyle[prop];
}
}
this.bindOutsideClickListener();
this.bindScrollListener();
this.bindResizeListener();

View File

@ -16,14 +16,23 @@
<slot name="paginatorRight"></slot>
</template>
</DTPaginator>
<div class="p-datatable-wrapper" v-if="!scrollable">
<table ref="table" role="grid">
<div class="p-datatable-wrapper" :style="{maxHeight: scrollHeight}">
<table ref="table" role="table" class="p-datatable-table">
<DTTableHeader :columnGroup="headerColumnGroup" :columns="columns" :rowGroupMode="rowGroupMode"
:groupRowsBy="groupRowsBy" :resizableColumns="resizableColumns" :allRowsSelected="allRowsSelected" :empty="empty"
:sortMode="sortMode" :sortField="d_sortField" :sortOrder="d_sortOrder" :multiSortMeta="d_multiSortMeta" :filters="d_filters" :filtersStore="filters" :filterDisplay="filterDisplay"
@column-click="onColumnHeaderClick($event)" @column-mousedown="onColumnHeaderMouseDown($event)" @filter-change="onFilterChange" @filter-apply="onFilterApply"
@column-dragstart="onColumnHeaderDragStart($event)" @column-dragover="onColumnHeaderDragOver($event)" @column-dragleave="onColumnHeaderDragLeave($event)" @column-drop="onColumnHeaderDrop($event)"
@column-resizestart="onColumnResizeStart($event)" @checkbox-change="toggleRowsWithCheckbox($event)" />
<DTTableBody :value="frozenValue" :frozenRow="true" class="p-datatable-frozen-tbody" :columns="columns" :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"
:expandedRowIcon="expandedRowIcon" :collapsedRowIcon="collapsedRowIcon" :expandedRows="expandedRows" :expandedRowKeys="d_expandedRowKeys" :expandedRowGroups="expandedRowGroups"
:editingRows="editingRows" :editingRowKeys="d_editingRowKeys" :templates="$slots" :loading="loading"
@rowgroup-toggle="toggleRowGroup" @row-click="onRowClick($event)" @row-rightclick="onRowRightClick($event)" @row-touchend="onRowTouchEnd" @row-keydown="onRowKeyDown"
@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)"
@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)"/>
<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"
:expandedRowIcon="expandedRowIcon" :collapsedRowIcon="collapsedRowIcon" :expandedRows="expandedRows" :expandedRowKeys="d_expandedRowKeys" :expandedRowGroups="expandedRowGroups"
@ -36,83 +45,6 @@
<DTTableFooter :columnGroup="footerColumnGroup" :columns="columns" />
</table>
</div>
<div class="p-datatable-scrollable-wrapper" v-else>
<DTScrollableView v-if="hasFrozenColumns" :scrollHeight="scrollHeight" :columns="frozenColumns" :frozenWidth="frozenWidth" :frozen="true"
:rowGroupMode="rowGroupMode" :groupRowsBy="groupRowsBy" :headerColumnGroup="frozenHeaderColumnGroup" :footerColumnGroup="frozenFooterColumnGroup">
<template #header="slotProps">
<DTTableHeader :columnGroup="slotProps.columnGroup" :columns="slotProps.columns" :rowGroupMode="rowGroupMode"
:groupRowsBy="groupRowsBy" :resizableColumns="resizableColumns" :allRowsSelected="allRowsSelected" :empty="empty"
:sortMode="sortMode" :sortField="d_sortField" :sortOrder="d_sortOrder" :multiSortMeta="d_multiSortMeta"
@column-click="onColumnHeaderClick($event)" @column-mousedown="onColumnHeaderMouseDown($event)"
@column-dragstart="onColumnHeaderDragStart($event)" @column-dragover="onColumnHeaderDragOver($event)" @column-dragleave="onColumnHeaderDragLeave($event)" @column-drop="onColumnHeaderDrop($event)"
@column-resizestart="onColumnResizeStart($event)" @checkbox-change="toggleRowsWithCheckbox($event)" />
</template>
<template #body="slotProps">
<DTTableBody :value="dataToRender" :columns="slotProps.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"
:expandedRowIcon="expandedRowIcon" :collapsedRowIcon="collapsedRowIcon" :expandedRows="expandedRows" :expandedRowKeys="d_expandedRowKeys" :expandedRowGroups="expandedRowGroups"
:editingRows="editingRows" :editingRowKeys="d_editingRowKeys" :templates="$slots" :loading="loading"
@rowgroup-toggle="toggleRowGroup" @row-click="onRowClick($event)" @row-rightclick="onRowRightClick($event)" @row-touchend="onRowTouchEnd" @row-keydown="onRowKeyDown"
@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)"
@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)"/>
</template>
<template #frozenbody="slotProps">
<DTTableBody v-if="frozenValue" :value="frozenValue" :columns="slotProps.columns" :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"
:expandedRowIcon="expandedRowIcon" :collapsedRowIcon="collapsedRowIcon" :expandedRows="expandedRows" :expandedRowKeys="d_expandedRowKeys" :expandedRowGroups="expandedRowGroups"
:editingRows="editingRows" :editingRowKeys="d_editingRowKeys" :templates="$slots" :loading="loading"
@rowgroup-toggle="toggleRowGroup" @row-click="onRowClick($event)" @row-rightclick="onRowRightClick($event)" @row-touchend="onRowTouchEnd" @row-keydown="onRowKeyDown"
@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)"
@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)"/>
</template>
<template #footer="slotProps">
<DTTableFooter :columnGroup="slotProps.columnGroup" :columns="slotProps.columns" />
</template>
</DTScrollableView>
<DTScrollableView :scrollHeight="scrollHeight" :columns="scrollableColumns" :frozenWidth="frozenWidth" :rows="rows"
:virtualScroll="virtualScroll" :virtualRowHeight="virtualRowHeight" :totalRecords="totalRecordsLength" @virtual-scroll="onVirtualScroll"
:rowGroupMode="rowGroupMode" :groupRowsBy="groupRowsBy" :headerColumnGroup="headerColumnGroup" :footerColumnGroup="footerColumnGroup">
<template #header="slotProps">
<DTTableHeader :columnGroup="slotProps.columnGroup" :columns="slotProps.columns" :rowGroupMode="rowGroupMode"
:groupRowsBy="groupRowsBy" :resizableColumns="resizableColumns" :allRowsSelected="allRowsSelected" :empty="empty"
:sortMode="sortMode" :sortField="d_sortField" :sortOrder="d_sortOrder" :multiSortMeta="d_multiSortMeta"
@column-click="onColumnHeaderClick($event)" @column-mousedown="onColumnHeaderMouseDown($event)"
@column-dragstart="onColumnHeaderDragStart($event)" @column-dragover="onColumnHeaderDragOver($event)" @column-dragleave="onColumnHeaderDragLeave($event)" @column-drop="onColumnHeaderDrop($event)"
@column-resizestart="onColumnResizeStart($event)" @checkbox-change="toggleRowsWithCheckbox($event)"
@operator-change="$emit('operator-change',$event)" @matchmode-change="$emit('matchmode-change',$event)"
@constraint-add="$emit('constraint-add',$event)" @constraint-remove="$emit('constraint-remove',$event)" @apply-click="$emit('apply-click',$event)" />
</template>
<template #body="slotProps">
<DTTableBody :value="dataToRender" :columns="slotProps.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"
:expandedRowIcon="expandedRowIcon" :collapsedRowIcon="collapsedRowIcon" :expandedRows="expandedRows" :expandedRowKeys="d_expandedRowKeys" :expandedRowGroups="expandedRowGroups"
:editingRows="editingRows" :editingRowKeys="d_editingRowKeys" :templates="$slots" :loading="loading"
@rowgroup-toggle="toggleRowGroup" @row-click="onRowClick($event)" @row-rightclick="onRowRightClick($event)" @row-touchend="onRowTouchEnd" @row-keydown="onRowKeyDown"
@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)"
@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)"/>
</template>
<template #frozenbody="slotProps">
<DTTableBody v-if="frozenValue" :value="frozenValue" :columns="slotProps.columns" :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"
:expandedRowIcon="expandedRowIcon" :collapsedRowIcon="collapsedRowIcon" :expandedRows="expandedRows" :expandedRowKeys="d_expandedRowKeys" :expandedRowGroups="expandedRowGroups"
:editingRows="editingRows" :editingRowKeys="d_editingRowKeys" :templates="$slots" :loading="loading"
@rowgroup-toggle="toggleRowGroup" @row-click="onRowClick($event)" @row-rightclick="onRowRightClick($event)" @row-touchend="onRowTouchEnd" @row-keydown="onRowKeyDown"
@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)"
@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)"/>
</template>
<template #footer="slotProps">
<DTTableFooter :columnGroup="slotProps.columnGroup" :columns="slotProps.columns" />
</template>
</DTScrollableView>
</div>
<DTPaginator v-if="paginatorBottom" :rows="d_rows" :first="d_first" :totalRecords="totalRecordsLength" :pageLinkSize="pageLinkSize" :template="paginatorTemplate" :rowsPerPageOptions="rowsPerPageOptions"
:currentPageReportTemplate="currentPageReportTemplate" class="p-paginator-bottom" @page="onPage($event)" :alwaysShow="alwaysShowPaginator">
<template #left v-if="$slots.paginatorLeft">
@ -135,7 +67,6 @@
import {ObjectUtils,DomHandler} from 'primevue/utils';
import {FilterMatchMode,FilterOperator,FilterService} from 'primevue/api';
import Paginator from 'primevue/paginator';
import ScrollableView from './ScrollableView.vue';
import TableHeader from './TableHeader.vue';
import TableBody from './TableBody.vue';
import TableFooter from './TableFooter.vue';
@ -352,6 +283,10 @@ export default {
type: Boolean,
default: false
},
scrollDirection: {
type: String,
default: "vertical"
},
scrollHeight: {
type: String,
default: null
@ -1097,34 +1032,16 @@ export default {
let nextColumnWidth = nextColumn.offsetWidth - delta;
if (newColumnWidth > 15 && nextColumnWidth > 15) {
if(this.scrollable) {
const scrollableView = this.findParentScrollableView(this.resizeColumnElement);
const scrollableBodyTable = DomHandler.findSingle(scrollableView, 'table.p-datatable-scrollable-body-table');
const scrollableHeaderTable = DomHandler.findSingle(scrollableView, 'table.p-datatable-scrollable-header-table');
const scrollableFooterTable = DomHandler.findSingle(scrollableView, 'table.p-datatable-scrollable-footer-table');
const resizeColumnIndex = DomHandler.index(this.resizeColumnElement);
this.resizeColGroup(scrollableHeaderTable, resizeColumnIndex, newColumnWidth, nextColumnWidth);
this.resizeColGroup(scrollableBodyTable, resizeColumnIndex, newColumnWidth, nextColumnWidth);
this.resizeColGroup(scrollableFooterTable, resizeColumnIndex, newColumnWidth, nextColumnWidth);
}
else {
this.resizeColumnElement.style.width = newColumnWidth + 'px';
if(nextColumn) {
nextColumn.style.width = nextColumnWidth + 'px';
}
}
}
}
else if (this.columnResizeMode === 'expand') {
if (this.scrollable) {
this.resizeScrollableTable(this.resizeColumnElement, newColumnWidth, delta);
}
else {
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,
@ -1290,19 +1207,6 @@ export default {
return parent;
}
},
findParentScrollableView(column) {
if (column) {
let parent = column.parentElement;
while (parent && !DomHandler.hasClass(parent, 'p-datatable-scrollable-view')) {
parent = parent.parentElement;
}
return parent;
}
else {
return null;
}
},
findColumnByKey(columns, key) {
if (columns && columns.length) {
for (let i = 0; i < columns.length; i++) {
@ -1315,38 +1219,6 @@ export default {
return null;
},
resizeScrollableTable(column, newColumnWidth, delta) {
const scrollableView = column ? this.findParentScrollableView(column) : this.$el;
const scrollableBody = DomHandler.findSingle(scrollableView, '.p-datatable-scrollable-body');
const scrollableHeader = DomHandler.findSingle(scrollableView, '.p-datatable-scrollable-header');
const scrollableFooter = DomHandler.findSingle(scrollableView, '.p-datatable-scrollable-footer');
const scrollableBodyTable = DomHandler.findSingle(scrollableBody, 'table.p-datatable-scrollable-body-table');
const scrollableHeaderTable = DomHandler.findSingle(scrollableHeader, 'table.p-datatable-scrollable-header-table');
const scrollableFooterTable = DomHandler.findSingle(scrollableFooter, 'table.p-datatable-scrollable-footer-table');
const scrollableBodyTableWidth = column ? scrollableBodyTable.offsetWidth + delta : newColumnWidth;
const scrollableHeaderTableWidth = column ? scrollableHeaderTable.offsetWidth + delta : newColumnWidth;
const isContainerInViewport = this.$el.offsetWidth >= parseFloat(scrollableBodyTableWidth);
let setWidth = (container, table, width, isContainerInViewport) => {
if (container && table) {
container.style.width = isContainerInViewport ? width + DomHandler.calculateScrollbarWidth(scrollableBody) + 'px' : 'auto'
table.style.width = width + 'px';
}
};
setWidth(scrollableBody, scrollableBodyTable, scrollableBodyTableWidth, isContainerInViewport);
setWidth(scrollableHeader, scrollableHeaderTable, scrollableHeaderTableWidth, isContainerInViewport);
setWidth(scrollableFooter, scrollableFooterTable, scrollableHeaderTableWidth, isContainerInViewport);
if (column) {
let resizeColumnIndex = DomHandler.index(column);
this.resizeColGroup(scrollableHeaderTable, resizeColumnIndex, newColumnWidth, null);
this.resizeColGroup(scrollableBodyTable, resizeColumnIndex, newColumnWidth, null);
this.resizeColGroup(scrollableFooterTable, resizeColumnIndex, newColumnWidth, null);
}
},
onRowMouseDown(event) {
if (DomHandler.hasClass(event.target, 'p-datatable-reorderablerow-handle'))
event.currentTarget.draggable = true;
@ -1603,8 +1475,7 @@ export default {
state.columnWidths = widths.join(',');
if (this.columnResizeMode === 'expand') {
state.tableWidth = this.scrollable ? DomHandler.findSingle(this.$el, '.p-datatable-scrollable-header-table').style.width :
DomHandler.getOuterWidth(this.$refs.table) + 'px';
state.tableWidth = DomHandler.getOuterWidth(this.$refs.table) + 'px';
}
},
restoreColumnWidths() {
@ -1612,28 +1483,11 @@ export default {
let widths = this.columnWidthsState.split(',');
if (this.columnResizeMode === 'expand' && this.tableWidthState) {
if (this.scrollable) {
this.resizeScrollableTable(null, this.tableWidthState, 0);
}
else {
this.$refs.table.style.width = this.tableWidthState;
this.$el.style.width = this.tableWidthState;
}
}
if (this.scrollable) {
let headerCols = DomHandler.find(this.$el, '.p-datatable-scrollable-header-table > colgroup > col');
let bodyCols = DomHandler.find(this.$el, '.p-datatable-scrollable-body-table > colgroup > col');
headerCols.forEach((col, index) => col.style.width = widths[index] + 'px');
bodyCols.forEach((col, index) => col.style.width = widths[index] + 'px');
}
else {
let headers = DomHandler.find(this.$refs.table, '.p-datatable-thead > tr > th');
headers.forEach((header, index) => header.style.width = widths[index] + 'px');
}
DomHandler.find(this.$refs.table, '.p-datatable-thead > tr > th').forEach((header, index) => header.style.width = widths[index] + 'px');
}
},
onCellEditInit(event) {
@ -1732,6 +1586,9 @@ export default {
'p-datatable-resizable': this.resizableColumns,
'p-datatable-resizable-fit': this.resizableColumns && this.columnResizeMode === 'fit',
'p-datatable-scrollable': this.scrollable,
'p-datatable-scrollable-vertical': this.scrollDirection === 'vertical',
'p-datatable-scrollable-horizontal': this.scrollDirection === 'horizontal',
'p-datatable-scrollable-both': this.scrollDirection === 'both',
'p-datatable-virtual-scrollable': this.virtualScroll,
'p-datatable-flex-scrollable': (this.scrollable && this.scrollHeight === 'flex')
}
@ -1766,33 +1623,6 @@ export default {
return cols;
},
frozenColumns() {
let frozenColumns = [];
for(let col of this.columns) {
if(this.columnProp(col, 'frozen')) {
frozenColumns = frozenColumns||[];
frozenColumns.push(col);
}
}
return frozenColumns;
},
scrollableColumns() {
let scrollableColumns = [];
for(let col of this.columns) {
if(!this.columnProp(col, 'frozen')) {
scrollableColumns = scrollableColumns||[];
scrollableColumns.push(col);
}
}
return scrollableColumns;
},
hasFrozenColumns() {
return this.frozenColumns.length > 0;
},
headerColumnGroup() {
const children = this.getChildren();
if (children) {
@ -1805,18 +1635,6 @@ export default {
return null;
},
frozenHeaderColumnGroup() {
const children = this.getChildren();
if (children) {
for (let child of children) {
if (child.type.name === 'columngroup' && this.columnProp(child, 'type') === 'frozenheader') {
return child;
}
}
}
return null;
},
footerColumnGroup() {
const children = this.getChildren();
if (children) {
@ -1829,18 +1647,6 @@ export default {
return null;
},
frozenFooterColumnGroup() {
const children = this.getChildren();
if (children) {
for (let child of children) {
if (child.type.name === 'columngroup' && this.columnProp(child, 'type') === 'frozenfooter') {
return child;
}
}
}
return null;
},
processedData() {
if (this.lazy) {
return this.value;
@ -1910,7 +1716,6 @@ export default {
},
components: {
'DTPaginator': Paginator,
'DTScrollableView': ScrollableView,
'DTTableHeader': TableHeader,
'DTTableBody': TableBody,
'DTTableFooter': TableFooter,
@ -1946,9 +1751,9 @@ export default {
justify-content: center;
}
.p-datatable-auto-layout > .p-datatable-wrapper {
/*.p-datatable-auto-layout > .p-datatable-wrapper {
overflow-x: auto;
}
}*/
.p-datatable-auto-layout > .p-datatable-wrapper > table {
table-layout: auto;
@ -1959,43 +1764,65 @@ export default {
}
/* Scrollable */
.p-datatable-scrollable-wrapper {
.p-datatable-scrollable .p-datatable-wrapper {
position: relative;
}
.p-datatable-scrollable-header,
.p-datatable-scrollable-footer {
overflow: hidden;
}
.p-datatable-scrollable-body {
overflow: auto;
position: relative;
}
.p-datatable-scrollable-body > table > .p-datatable-tbody > tr:first-child > td {
border-top: 0 none;
.p-datatable-scrollable .p-datatable-table {
display: block;
}
.p-datatable-virtual-table {
position: absolute;
.p-datatable-scrollable .p-datatable-thead,
.p-datatable-scrollable .p-datatable-tbody,
.p-datatable-scrollable .p-datatable-tfoot {
display: block;
}
/* Frozen Columns */
.p-datatable-frozen-view .p-datatable-scrollable-body {
overflow: hidden;
.p-datatable-scrollable .p-datatable-thead > tr,
.p-datatable-scrollable .p-datatable-tbody > tr,
.p-datatable-scrollable .p-datatable-tfoot > tr {
display: flex;
flex-wrap: nowrap;
width: 100%;
}
.p-datatable-frozen-view > .p-datatable-scrollable-body > table > .p-datatable-tbody > tr > td:last-child {
border-right: 0 none;
.p-datatable-scrollable .p-datatable-thead > tr > th,
.p-datatable-scrollable .p-datatable-tbody > tr > td,
.p-datatable-scrollable .p-datatable-tfoot > tr > td {
flex: 1 1 0;
}
.p-datatable-unfrozen-view {
position: absolute;
.p-datatable-scrollable .p-datatable-thead {
position: sticky;
top: 0;
z-index: 1;
}
.p-datatable-scrollable .p-datatable-frozen-tbody {
position: sticky;
}
.p-datatable-scrollable .p-datatable-tfoot {
position: sticky;
bottom: 0;
z-index: 1;
}
.p-datatable-scrollable .p-frozen-column {
position: sticky;
background: inherit;
}
.p-datatable-scrollable-both .p-datatable-thead > tr > th,
.p-datatable-scrollable-both .p-datatable-tbody > tr > td,
.p-datatable-scrollable-both .p-datatable-tfoot > tr > td,
.p-datatable-scrollable-horizontal .p-datatable-thead > tr > th
.p-datatable-scrollable-horizontal .p-datatable-tbody > tr > td,
.p-datatable-scrollable-horizontal .p-datatable-tfoot > tr > td {
flex: 0 0 auto;
}
/* Flex Scrollable */
.p-datatable-flex-scrollable {
display: flex;
flex-direction: column;
@ -2003,18 +1830,13 @@ export default {
height: 100%;
}
.p-datatable-flex-scrollable .p-datatable-scrollable-wrapper,
.p-datatable-flex-scrollable .p-datatable-scrollable-view {
.p-datatable-flex-scrollable .p-datatable-wrapper {
display: flex;
flex-direction: column;
flex: 1;
height: 100%;
}
.p-datatable-flex-scrollable .p-datatable-scrollable-body {
flex: 1;
}
/* Resizable */
.p-datatable-resizable > .p-datatable-wrapper {
overflow-x: auto;

View File

@ -0,0 +1,66 @@
<template>
<td :style="containerStyle" :class="containerClass" role="cell"
:colspan="columnProp('colspan')" :rowspan="columnProp('rowspan')">
<component :is="column.children.footer" :column="column" v-if="column.children && column.children.footer"/>
{{columnProp('footer')}}
</td>
</template>
<script>
import {DomHandler} from 'primevue/utils';
export default {
props: {
column: {
type: null,
default: null
}
},
data() {
return {
styleObject: {
left: '0px'
}
}
},
mounted() {
if (this.columnProp('frozen')) {
this.updateStickyPosition();
}
},
updated() {
if (this.columnProp('frozen')) {
this.updateStickyPosition();
}
},
methods: {
columnProp(prop) {
return this.column.props ? ((this.column.type.props[prop].type === Boolean && this.column.props[prop] === '') ? true : this.column.props[prop]) : null;
},
updateStickyPosition() {
if (this.columnProp('frozen')) {
let left = 0;
let prev = this.$el.previousElementSibling;
if (prev) {
left = DomHandler.getOuterWidth(prev) + parseFloat(prev.style.left);
}
this.styleObject.left = left + 'px';
}
}
},
computed: {
containerClass() {
return [this.columnProp('footerClass'), this.columnProp('class'), {
'p-frozen-column': this.columnProp('frozen')
}];
},
containerStyle() {
let bodyStyle = this.columnProp('footerStyle');
let columnStyle = this.columnProp('style');
return this.columnProp('frozen') ? [columnStyle, bodyStyle, this.styleObject]: [columnStyle, bodyStyle];
}
}
}
</script>

View File

@ -0,0 +1,225 @@
<template>
<th :style="containerStyle" :class="containerClass" :tabindex="columnProp('sortable') ? '0' : null" role="cell"
@click="onClick" @keydown="onKeyDown" @mousedown="onMouseDown"
@dragstart="onDragStart" @dragover="onDragOver" @dragleave="onDragLeave" @drop="onDrop"
:colspan="columnProp('colspan')" :rowspan="columnProp('rowspan')" :aria-sort="ariaSort">
<span class="p-column-resizer" @mousedown="onResizeStart" v-if="resizableColumns"></span>
<div class="p-column-header-content">
<component :is="col.children.header" :column="column" v-if="column.children && column.children.header"/>
<span class="p-column-title" v-if="columnProp('header')">{{columnProp('header')}}</span>
<span v-if="columnProp('sortable')" :class="sortableColumnIcon"></span>
<span v-if="isMultiSorted()" class="p-sortable-column-badge">{{getMultiSortMetaIndex() + 1}}</span>
<DTHeaderCheckbox :checked="allRowsSelected" @change="onHeaderCheckboxChange" :disabled="empty" v-if="columnProp('selectionMode') ==='multiple' && filterDisplay !== 'row'" />
<DTColumnFilter v-if="filterDisplay === 'menu' && column.children && column.children.filter" :field="columnProp('filterField')||columnProp('field')" :type="columnProp('dataType')" display="menu"
:showMenu="columnProp('showFilterMenu')" :filterElement="column.children && column.children.filter"
:filterHeaderTemplate="column.children && column.children.filterheader" :filterFooterTemplate="column.children && column.children.filterfooter"
:filterClearTemplate="column.children && column.children.filterclear" :filterApplyTemplate="column.children && column.children.filterapply"
:filters="filters" :filtersStore="filtersStore" @filter-change="$emit('filter-change', $event)" @filter-apply="$emit('filter-apply')" :filterMenuStyle="columnProp('filterMenuStyle')" :filterMenuClass="columnProp('filterMenuClass')"
:showOperator="columnProp('showFilterOperator')" :showClearButton="columnProp('showClearButton')" :showApplyButton="columnProp('showApplyButton')"
:showMatchModes="columnProp('showFilterMatchModes')" :showAddButton="columnProp('showAddButton')" :matchModeOptions="columnProp('filterMatchModeOptions')" :maxConstraints="columnProp('maxConstraints')"
@operator-change="$emit('operator-change',$event)" @matchmode-change="$emit('matchmode-change', $event)" @constraint-add="$emit('constraint-add', $event)" @constraint-remove="$emit('constraint-remove', $event)" @apply-click="$emit('apply-click',$event)"/>
</div>
</th>
</template>
<script>
import {DomHandler} from 'primevue/utils';
import HeaderCheckbox from './HeaderCheckbox.vue';
import ColumnFilter from './ColumnFilter';
export default {
emits: ['column-click', 'column-mousedown', 'column-dragstart', 'column-dragover', 'column-dragleave', 'column-drop',
'column-resizestart', 'checkbox-change', 'filter-change', 'filter-apply',
'operator-change', 'matchmode-change', 'constraint-add', 'constraint-remove', 'filter-clear', 'apply-click'],
props: {
column: {
type: Object,
default: null
},
resizableColumns: {
type: Boolean,
default: false
},
sortMode: {
type: String,
default: 'single'
},
sortField: {
type: [String, Function],
default: null
},
sortOrder: {
type: Number,
default: null
},
multiSortMeta: {
type: Array,
default: null
},
allRowsSelected: {
type: Boolean,
default: false
},
empty: {
type: Boolean,
default: false
},
filterDisplay: {
type: String,
default: null
},
filters: {
type: Object,
default: null
},
filtersStore: {
type: Object,
default: null
},
filterColumn: {
type: Boolean,
default: false
}
},
data() {
return {
styleObject: {
left: '0px'
}
}
},
mounted() {
if (this.columnProp('frozen')) {
this.updateStickyPosition();
}
},
updated() {
if (this.columnProp('frozen')) {
this.updateStickyPosition();
}
},
methods: {
columnProp(prop) {
return this.column.props ? ((this.column.type.props[prop].type === Boolean && this.column.props[prop] === '') ? true : this.column.props[prop]) : null;
},
onClick(event) {
this.$emit('column-click', {originalEvent: event, column: this.column});
},
onKeyDown(event) {
if (event.which === 13 && event.currentTarget.nodeName === 'TH' && DomHandler.hasClass(event.currentTarget, 'p-sortable-column')) {
this.$emit('column-click', {originalEvent: event, column: this.column});
}
},
onMouseDown(event) {
this.$emit('column-mousedown', {originalEvent: event, column: this.column});
},
onDragStart(event) {
this.$emit('column-dragstart', event);
},
onDragOver(event) {
this.$emit('column-dragover', event);
},
onDragLeave(event) {
this.$emit('column-dragleave', event);
},
onDrop(event) {
this.$emit('column-drop', event);
},
onResizeStart(event) {
this.$emit('column-resizestart', event);
},
getMultiSortMetaIndex() {
let index = -1;
for (let i = 0; i < this.multiSortMeta.length; i++) {
let meta = this.multiSortMeta[i];
if (meta.field === this.columnProp('field') || meta.field === this.columnProp('sortField')) {
index = i;
break;
}
}
return index;
},
isMultiSorted() {
return this.columnProp('sortable') && this.getMultiSortMetaIndex() > -1
},
isColumnSorted() {
return this.sortMode === 'single' ? (this.sortField && (this.sortField === this.columnProp('field') || this.sortField === this.columnProp('sortField'))) : this.isMultiSorted();
},
updateStickyPosition() {
if (this.columnProp('frozen')) {
let left = 0;
let prev = this.$el.previousElementSibling;
if (prev) {
left = DomHandler.getOuterWidth(prev) + parseFloat(prev.style.left);
}
this.styleObject.left = left + 'px';
}
},
onHeaderCheckboxChange(event) {
this.$emit('checkbox-change', event);
}
},
computed: {
containerClass() {
return [this.filterColumn ? this.columnProp('headerClass') : this.columnProp('filterHeaderClass'), this.columnProp('class'), {
'p-sortable-column': this.columnProp('sortable'),
'p-resizable-column': this.resizableColumns,
'p-highlight': this.isColumnSorted(),
'p-filter-column': this.filterColumn,
'p-frozen-column': this.columnProp('frozen')
}];
},
containerStyle() {
let headerStyle = this.filterColumn ? this.columnProp('filterHeaderStyle'): this.columnProp('headerStyle');
let columnStyle = this.columnProp('style');
return this.columnProp('frozen') ? [columnStyle, headerStyle, this.styleObject]: [columnStyle, headerStyle];
},
sortableColumnIcon() {
let sorted = false;
let sortOrder = null;
if (this.sortMode === 'single') {
sorted = this.sortField && (this.sortField === this.columnProp('field') || this.sortField === this.columnProp('sortField'));
sortOrder = sorted ? this.sortOrder: 0;
}
else if (this.sortMode === 'multiple') {
let metaIndex = this.getMultiSortMetaIndex();
if (metaIndex > -1) {
sorted = true;
sortOrder = this.multiSortMeta[metaIndex].order;
}
}
return [
'p-sortable-column-icon pi pi-fw', {
'pi-sort-alt': !sorted,
'pi-sort-amount-up-alt': sorted && sortOrder > 0,
'pi-sort-amount-down': sorted && sortOrder < 0
}
];
},
ariaSort() {
if (this.columnProp('sortable')) {
const sortIcon = this.getSortableColumnIcon();
if (sortIcon[1]['pi-sort-amount-down'])
return 'descending';
else if (sortIcon[1]['pi-sort-amount-up-alt'])
return 'ascending';
else
return 'none';
}
else {
return null;
}
}
},
components: {
'DTHeaderCheckbox': HeaderCheckbox,
'DTColumnFilter': ColumnFilter
}
}
</script>

View File

@ -1,238 +0,0 @@
<template>
<div :class="containerClass" :style="containerStyle">
<div class="p-datatable-scrollable-header" ref="scrollHeader" @scroll="onHeaderScroll">
<div class="p-datatable-scrollable-header-box" ref="scrollHeaderBox">
<table class="p-datatable-scrollable-header-table">
<colgroup>
<template v-for="(col,i) of columns">
<col v-if="shouldRenderCol(col)" :key="columnProp(col,'columnKey')||columnProp(col,'field')||i" :style="columnProp(col,'headerStyle')" :class="columnProp(col,'headerClass')"/>
</template>
</colgroup>
<slot name="header" :columns="columns" :columnGroup="headerColumnGroup"></slot>
<slot name="frozenbody" :columns="columns"></slot>
</table>
</div>
</div>
<div class="p-datatable-scrollable-body" ref="scrollBody" @scroll="onBodyScroll" :style="bodyStyle">
<table ref="scrollTable" :class="bodyTableClass" :style="bodyTableStyle">
<colgroup>
<template v-for="(col,i) of columns">
<col v-if="shouldRenderCol(col)" :key="columnProp(col,'columnKey')||columnProp(col,'field')||i"
:style="columnProp(col,'bodyStyle')" :class="columnProp(col,'bodyClass')"/>
</template>
</colgroup>
<slot name="body" :columns="columns"></slot>
</table>
<table ref="loadingTable" :style="{top:'0', display: 'none'}" class="p-datatable-scrollable-body-table p-datatable-loading-virtual-table p-datatable-virtual-table" v-if="virtualScroll">
<colgroup>
<col v-for="(col,i) of columns" :key="columnProp(col,'columnKey')||columnProp(col,'field')||i"
:style="columnProp(col,'bodyStyle')" :class="columnProp(col,'bodyClass')" />
</colgroup>
<DTTableLoadingBody :columns="columns" :rows="rows" />
</table>
<div class="p-datatable-virtual-scroller" ref="virtualScroller"></div>
</div>
<div class="p-datatable-scrollable-footer" ref="scrollFooter">
<div class="p-datatable-scrollable-footer-box" ref="scrollFooterBox">
<table class="p-datatable-scrollable-footer-table">
<colgroup>
<template v-for="(col,i) of columns">
<col v-if="shouldRenderCol(col)" :key="columnProp(col,'columnKey')||columnProp(col,'field')||i"
:style="columnProp(col,'footerStyle')" :class="columnProp(col,'footerClass')" />
</template>
</colgroup>
<slot name="footer" :columns="columns" :columnGroup="footerColumnGroup"></slot>
</table>
</div>
</div>
</div>
</template>
<script>
import {DomHandler} from 'primevue/utils';
import TableLoadingBody from './TableLoadingBody.vue';
export default {
emits: ['virtual-scroll'],
props: {
frozen: {
type: Boolean,
default: false
},
frozenWidth: {
type: String,
default: null
},
columns: {
type: null,
default: null
},
headerColumnGroup: {
type: null,
default: null
},
footerColumnGroup: {
type: null,
default: null
},
scrollHeight: {
type: String,
default: null
},
virtualScroll: {
type: Boolean,
default: false
},
virtualRowHeight: {
type: Number,
default: null
},
rows: {
type: Number,
default: null,
},
totalRecords: {
type: Number,
default: 0
},
rowGroupMode: {
type: String,
default: null
},
groupRowsBy: {
type: [Array,String],
default: null
}
},
virtualScrollCallback: null,
mounted() {
if (!this.frozen)
this.alignScrollBar();
else
this.$refs.scrollBody.style.paddingBottom = DomHandler.calculateScrollbarWidth() + 'px';
if (this.virtualScroll) {
this.$refs.virtualScroller.style.height = this.totalRecords * this.virtualRowHeight + 'px';
}
},
updated() {
if (this.virtualScrollCallback) {
this.virtualScrollCallback();
this.virtualScrollCallback = null;
}
},
watch: {
totalRecords(newValue) {
if (this.virtualScroll) {
this.$refs.virtualScroller.style.height = newValue * this.virtualRowHeight + 'px';
}
}
},
methods: {
columnProp(col, prop) {
return col.props ? ((col.type.props[prop].type === Boolean && col.props[prop] === '') ? true : col.props[prop]) : null;
},
onHeaderScroll() {
this.$refs.scrollHeader.scrollLeft = 0;
},
onBodyScroll() {
let frozenView = this.$el.previousElementSibling;
let frozenScrollBody;
if (frozenView) {
frozenScrollBody = DomHandler.findSingle(frozenView, '.p-datatable-scrollable-body');
}
if (frozenScrollBody) {
frozenScrollBody.scrollTop = this.$refs.scrollBody.scrollTop;
}
this.$refs.scrollHeaderBox.style.marginLeft = -1 * this.$refs.scrollBody.scrollLeft + 'px';
if (this.$refs.scrollFooterBox) {
this.$refs.scrollFooterBox.style.marginLeft = -1 * this.$refs.scrollBody.scrollLeft + 'px';
}
if (this.virtualScroll) {
let viewport = DomHandler.getClientHeight(this.$refs.scrollBody);
let tableHeight = DomHandler.getOuterHeight(this.$refs.scrollTable);
let pageHeight = this.virtualRowHeight * this.rows;
let virtualTableHeight = DomHandler.getOuterHeight(this.$refs.virtualScroller);
let pageCount = (virtualTableHeight / pageHeight)||1;
let scrollBodyTop = this.$refs.scrollTable.style.top||'0';
if(this.$refs.scrollBody.scrollTop + viewport > parseFloat(scrollBodyTop) + tableHeight || this.$refs.scrollBody.scrollTop < parseFloat(scrollBodyTop)) {
if (this.$refs.loadingTable) {
this.$refs.loadingTable.style.display = 'table';
this.$refs.loadingTable.style.top = this.$refs.scrollBody.scrollTop + 'px';
}
let page = Math.floor((this.$refs.scrollBody.scrollTop * pageCount) / (this.$refs.scrollBody.scrollHeight)) + 1;
this.$emit('virtual-scroll', {
page: page
});
this.virtualScrollCallback = () => {
if (this.$refs.loadingTable) {
this.$refs.loadingTable.style.display = 'none';
}
this.$refs.scrollTable.style.top = ((page - 1) * pageHeight) + 'px';
}
}
}
},
alignScrollBar() {
let scrollBarWidth = DomHandler.calculateScrollbarWidth();
this.$refs.scrollHeaderBox.style.paddingRight = scrollBarWidth + 'px';
if (this.$refs.scrollFooterBox) {
this.$refs.scrollFooterBox.style.paddingRight = scrollBarWidth + 'px';
}
},
shouldRenderCol(column) {
if (this.rowGroupMode && this.rowGroupMode === 'subheader') {
return this.groupRowsBy !== this.columnProp(column, 'field');
}
return true;
}
},
computed: {
containerClass() {
return ['p-datatable-scrollable-view', {'p-datatable-frozen-view': this.frozen, 'p-datatable-unfrozen-view': !this.frozen && this.frozenWidth}];
},
containerStyle() {
if (this.frozenWidth) {
if (this.frozen) {
return {
width: this.frozenWidth
};
}
else {
return {
width: 'calc(100% - ' + this.frozenWidth + ')',
left: this.frozenWidth
}
}
}
else {
return null;
}
},
bodyTableClass() {
return ['p-datatable-scrollable-body-table', {'p-datatable-virtual-table': this.virtualScroll}];
},
bodyTableStyle() {
return this.virtualScroll ? {top: '0'} : null;
},
bodyStyle() {
return {
maxHeight: this.scrollHeight !== 'flex' ? this.scrollHeight: null,
overflowY: !this.frozen && this.scrollHeight ? 'scroll': null
}
}
},
components: {
'DTTableLoadingBody': TableLoadingBody
}
}
</script>

View File

@ -1,8 +1,8 @@
<template>
<tbody class="p-datatable-tbody">
<tbody class="p-datatable-tbody" role="rowgroup">
<template v-if="!empty">
<template v-for="(rowData, index) of value">
<tr class="p-rowgroup-header" v-if="templates['groupheader'] && rowGroupMode === 'subheader' && shouldRenderRowGroupHeader(value, rowData, index)" :key="getRowKey(rowData, index) + '_subheader'">
<template v-for="(rowData, index) of value" :key="getRowKey(rowData, index) + '_subheader'">
<tr class="p-rowgroup-header" v-if="templates['groupheader'] && rowGroupMode === 'subheader' && shouldRenderRowGroupHeader(value, rowData, index)" role="row">
<td :colspan="columnsLength - 1">
<button class="p-row-toggler p-link" @click="onRowGroupToggle($event, rowData)" v-if="expandableRowGroups" type="button">
<span :class="rowGroupTogglerIcon(rowData)"></span>
@ -13,9 +13,9 @@
<tr :class="getRowClass(rowData)" :key="getRowKey(rowData, index)"
v-if="expandableRowGroups ? isRowGroupExpanded(rowData): true"
@click="onRowClick($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)">
<template v-for="(col,i) of columns">
<DTBodyCell v-if="shouldRenderBodyCell(value, col, index)" :key="columnProp(col,'columnKey')||columnProp(col,'field')||i" :rowData="rowData" :column="col" :index="index" :selected="isSelected(rowData)"
@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">
<DTBodyCell v-if="shouldRenderBodyCell(value, col, index)" :rowData="rowData" :column="col" :index="index" :selected="isSelected(rowData)"
:rowTogglerIcon="columnProp(col,'expander') ? rowTogglerIcon(rowData): null"
:rowspan="rowGroupMode === 'rowspan' ? calculateRowGroupSize(value, col, index) : null"
:editMode="editMode" :editing="editMode === 'row' && isRowEditing(rowData)"
@ -24,17 +24,17 @@
@row-edit-init="onRowEditInit($event)" @row-edit-save="onRowEditSave($event)" @row-edit-cancel="onRowEditCancel($event)"/>
</template>
</tr>
<tr class="p-datatable-row-expansion" v-if="templates['expansion'] && expandedRows && isRowExpanded(rowData)" :key="getRowKey(rowData, index) + '_expansion'">
<tr class="p-datatable-row-expansion" v-if="templates['expansion'] && expandedRows && isRowExpanded(rowData)" :key="getRowKey(rowData, index) + '_expansion'" role="row">
<td :colspan="columnsLength">
<component :is="templates['expansion']" :data="rowData" :index="index" />
</td>
</tr>
<tr class="p-rowgroup-footer" v-if="templates['groupfooter'] && rowGroupMode === 'subheader' && shouldRenderRowGroupFooter(value, rowData, index)" :key="getRowKey(rowData, index) + '_subfooter'">
<tr class="p-rowgroup-footer" v-if="templates['groupfooter'] && rowGroupMode === 'subheader' && shouldRenderRowGroupFooter(value, rowData, index)" :key="getRowKey(rowData, index) + '_subfooter'" role="row">
<component :is="templates['groupfooter']" :data="rowData" :index="index" />
</tr>
</template>
</template>
<tr v-else class="p-datatable-emptymessage">
<tr v-else class="p-datatable-emptymessage" role="row">
<td :colspan="columnsLength">
<component :is="templates.empty" v-if="templates.empty && !loading" />
<component :is="templates.loading" v-if="templates.loading && loading" />
@ -44,7 +44,7 @@
</template>
<script>
import {ObjectUtils} from 'primevue/utils';
import {ObjectUtils,DomHandler} from 'primevue/utils';
import BodyCell from './BodyCell.vue';
export default {
@ -61,6 +61,10 @@ export default {
type: null,
default: null
},
frozenRow: {
type: Boolean,
default: false
},
empty: {
type: Boolean,
default: false
@ -150,6 +154,16 @@ export default {
default: null
}
},
mounted() {
if (this.frozenRow) {
this.updateStickyPosition();
}
},
updated() {
if (this.frozenRow) {
this.updateStickyPosition();
}
},
methods: {
columnProp(col, prop) {
return col.props ? ((col.type.props[prop].type === Boolean && col.props[prop] === '') ? true : col.props[prop]) : null;
@ -407,6 +421,9 @@ export default {
},
onRowEditCancel(event) {
this.$emit('row-edit-cancel', event);
},
updateStickyPosition() {
this.$el.style.top = DomHandler.getOuterHeight(this.$el.previousElementSibling) + 'px';
}
},
computed: {

View File

@ -1,25 +1,23 @@
<template>
<tfoot class="p-datatable-tfoot" v-if="hasFooter">
<tr v-if="!columnGroup">
<td v-for="(col,i) of columns" :key="columnProp(col, 'columnKey')||columnProp(col, 'field')||i" :style="columnProp(col, 'footerStyle')" :class="columnProp(col, 'footerClass')"
:colspan="columnProp(col, 'colspan')" :rowspan="columnProp(col, 'rowspan')">
<component :is="col.children.footer" :column="col" v-if="col.children && col.children.footer"/>
{{columnProp(col, 'footer')}}
</td>
<tfoot class="p-datatable-tfoot" v-if="hasFooter" role="rowgroup">
<tr v-if="!columnGroup" role="row">
<template v-for="(col,i) of columns" :key="columnProp(col,'columnKey')||columnProp(col,'field')||i" >
<DTFooterCell :column="col" />
</template>
</tr>
<template v-else>
<tr v-for="(row,i) of columnGroup.children.default()" :key="i">
<td v-for="(col,i) of row.children.default()" :key="columnProp(col, 'columnKey')||columnProp(col, 'field')||i" :style="columnProp(col, 'footerStyle')" :class="columnProp(col, 'footerClass')"
:colspan="columnProp(col, 'colspan')" :rowspan="columnProp(col, 'rowspan')">
<component :is="col.children.footer" :column="col" v-if="col.children && col.children.footer"/>
{{columnProp(col, 'footer')}}
</td>
<template v-for="(col,j) of row.children.default()" :key="columnProp(col,'columnKey')||columnProp(col,'field')||j">
<DTFooterCell :column="col" />
</template>
</tr>
</template>
</tfoot>
</template>
<script>
import FooterCell from './FooterCell';
export default {
props: {
columnGroup: {
@ -54,6 +52,9 @@ export default {
return hasFooter;
}
},
components: {
'DTFooterCell': FooterCell
}
}
</script>

View File

@ -485,4 +485,15 @@ export default class DomHandler {
this.hasClass(element.parentElement, 'p-checkbox') || this.hasClass(element.parentElement, 'p-radiobutton')
);
}
static applyStyle(element, style) {
if (typeof style === 'string') {
element.style.cssText = this.style;
}
else {
for (let prop in this.style) {
element.style[prop] = style[prop];
}
}
}
}

View File

@ -10,7 +10,7 @@
<div class="content-section implementation">
<div class="card">
<h5>Vertical</h5>
<DataTable :value="customers" :scrollable="true" scrollHeight="200px" :loading="loading">
<DataTable :value="customers" :scrollable="true" scrollHeight="400px" :loading="loading">
<Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column>
<Column field="representative.name" header="Representative"></Column>
@ -20,7 +20,7 @@
<div class="card">
<h5>Flexible Scroll</h5>
<p>Flex scroll feature makes the scrollable viewport section dynamic so that it can grow or shrink relative to the parent size of the table.
<p>Flex scroll feature makes the scrollable viewport section dynamic insteaf of a fixed value so that it can grow or shrink relative to the parent size of the table.
Click the button below to display a maximizable Dialog where data viewport adjusts itself according to the size changes.</p>
<Button label="Show" icon="pi pi-external-link" @click="openDialog" />
@ -31,13 +31,13 @@
<Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column>
<Column field="representative.name" header="Representative"></Column>
<Column field="status" header="Company"></Column>
<Column field="status" header="Status"></Column>
</DataTable>
<template #footer>
<Button label="Ok" icon="pi pi-check" @click="closeDialog" />
</template>
</Dialog>
<!--
<div class="card">
<h5>Virtual Scroll</h5>
<DataTable :value="virtualCustomers" :scrollable="true" scrollHeight="200px" :lazy="true" :rows="20" :loading="loading"
@ -63,25 +63,31 @@
</template>
</Column>
</DataTable>
</div>
</div>-->
<div class="card">
<h5>Horizontal and Vertical</h5>
<DataTable :value="customers" :scrollable="true" scrollHeight="200px" style="width: 600px" :loading="loading">
<Column field="id" header="Id" headerStyle="width: 250px" columnKey="id"></Column>
<Column field="name" header="Name" headerStyle="width: 250px" columnKey="name"></Column>
<Column field="country.name" header="Country" headerStyle="width: 250px" columnKey="country"></Column>
<Column field="date" header="Date" headerStyle="width: 250px" columnKey="date"></Column>
<Column field="company" header="Company" headerStyle="width: 250px" columnKey="company"></Column>
<Column field="status" header="Status" headerStyle="width: 250px" columnKey="status"></Column>
<Column field="activity" header="Activity" headerStyle="width: 250px" columnKey="activity"></Column>
<Column field="representative.name" header="Representative" headerStyle="width: 250px" columnKey="representative"></Column>
<h5>Horizontal and Vertical with Footer</h5>
<DataTable :value="customers" :scrollable="true" scrollHeight="400px" :loading="loading" scrollDirection="both">
<Column field="id" header="Id" footer="Id" :style="{width:'250px'}"></Column>
<Column field="name" header="Name" footer="Name" :style="{width:'250px'}"></Column>
<Column field="country.name" header="Country" footer="Country" :style="{width:'250px'}"></Column>
<Column field="date" header="Date" footer="Date" :style="{width:'250px'}"></Column>
<Column field="balance" header="Balance" footer="Balance" :style="{width:'250px'}">
<template #body="{data}">
{{formatCurrency(data.balance)}}
</template>
</Column>
<Column field="company" header="Company" footer="Company" :style="{width:'250px'}"></Column>
<Column field="status" header="Status" footer="Status" :style="{width:'250px'}"></Column>
<Column field="activity" header="Activity" footer="Activity" :style="{width:'250px'}"></Column>
<Column field="representative.name" header="Representative" footer="Representative" :style="{width:'250px'}"></Column>
</DataTable>
</div>
<div class="card">
<h5>Frozen Rows</h5>
<DataTable :value="customers" :frozenValue="frozenValue" :scrollable="true" scrollHeight="200px" :loading="loading">
<DataTable :value="customers" :frozenValue="frozenValue" :scrollable="true" scrollHeight="400px" :loading="loading">
<Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column>
<Column field="representative.name" header="Representative"></Column>
@ -91,19 +97,25 @@
<div class="card">
<h5>Frozen Columns</h5>
<DataTable :value="customers" :scrollable="true" scrollHeight="200px" frozenWidth="300px" :loading="loading">
<Column field="name" header="Name" headerStyle="width: 300px" columnKey="name" :frozen="true">
<DataTable :value="customers" :scrollable="true" scrollHeight="400px" :loading="loading" scrollDirection="both">
<Column field="name" header="Name" :style="{width:'250px'}" frozen>
<template #body="slotProps">
<span style="font-weight: 700">{{slotProps.data.name}}</span>
</template>
</Column>
<Column field="id" header="Id" headerStyle="width: 300px" columnKey="id"></Column>
<Column field="country.name" header="Country" headerStyle="width: 300px" columnKey="country"></Column>
<Column field="date" header="Date" headerStyle="width: 300px" columnKey="date"></Column>
<Column field="company" header="Country" headerStyle="width: 300px" columnKey="company"></Column>
<Column field="status" header="Status" headerStyle="width: 300px" columnKey="status"></Column>
<Column field="activity" header="Activity" headerStyle="width: 300px" columnKey="activity"></Column>
<Column field="representative.name" header="Representative" headerStyle="width: 300px" columnKey="representative"></Column>
<Column field="id" header="Id" :style="{width:'250px'}"></Column>
<Column field="name" header="Name" :style="{width:'250px'}"></Column>
<Column field="country.name" header="Country" :style="{width:'250px'}"></Column>
<Column field="date" header="Date" :style="{width:'250px'}"></Column>
<Column field="balance" header="Balance" :style="{width:'250px'}">
<template #body="{data}">
{{formatCurrency(data.balance)}}
</template>
</Column>
<Column field="company" header="Company" :style="{width:'250px'}"></Column>
<Column field="status" header="Status" :style="{width:'250px'}"></Column>
<Column field="activity" header="Activity" :style="{width:'250px'}"></Column>
<Column field="representative.name" header="Representative" :style="{width:'250px'}"></Column>
</DataTable>
</div>
</div>
@ -128,7 +140,7 @@
&lt;div class="card"&gt;
&lt;h5&gt;Flexible Scroll&lt;/h5&gt;
&lt;p&gt;Flex scroll feature makes the scrollable viewport section dynamic so that it can grow or shrink relative to the parent size of the table.
Click the button below to display a maximizable Dialog where data viewport adjusts itself according to the size changes.&lt;/p&gt;
click the button below to display a maximizable Dialog where data viewport adjusts itself according to the size changes.&lt;/p&gt;
&lt;Button label="Show" icon="pi pi-external-link" @click="openDialog" /&gt;
&lt;/div&gt;
@ -175,14 +187,14 @@
&lt;div class="card"&gt;
&lt;h5&gt;Horizontal and Vertical&lt;/h5&gt;
&lt;DataTable :value="customers" :scrollable="true" scrollHeight="200px" style="width: 600px" :loading="loading"&gt;
&lt;Column field="id" header="Id" headerStyle="width: 250px" columnKey="id"&gt;&lt;/Column&gt;
&lt;Column field="name" header="Name" headerStyle="width: 250px" columnKey="name"&gt;&lt;/Column&gt;
&lt;Column field="country.name" header="Country" headerStyle="width: 250px" columnKey="country"&gt;&lt;/Column&gt;
&lt;Column field="date" header="Date" headerStyle="width: 250px" columnKey="date"&gt;&lt;/Column&gt;
&lt;Column field="company" header="Company" headerStyle="width: 250px" columnKey="company"&gt;&lt;/Column&gt;
&lt;Column field="status" header="Status" headerStyle="width: 250px" columnKey="status"&gt;&lt;/Column&gt;
&lt;Column field="activity" header="Activity" headerStyle="width: 250px" columnKey="activity"&gt;&lt;/Column&gt;
&lt;Column field="representative.name" header="Representative" headerStyle="width: 250px" columnKey="representative"&gt;&lt;/Column&gt;
&lt;Column field="id" header="Id" :headerStyle="{width:'250px'}" columnKey="id"&gt;&lt;/Column&gt;
&lt;Column field="name" header="Name" :headerStyle="{width:'250px'}" columnKey="name"&gt;&lt;/Column&gt;
&lt;Column field="country.name" header="Country" :headerStyle="{width:'250px'}" columnKey="country"&gt;&lt;/Column&gt;
&lt;Column field="date" header="Date" :headerStyle="{width:'250px'}" columnKey="date"&gt;&lt;/Column&gt;
&lt;Column field="company" header="Company" :headerStyle="{width:'250px'}" columnKey="company"&gt;&lt;/Column&gt;
&lt;Column field="status" header="Status" :headerStyle="{width:'250px'}" columnKey="status"&gt;&lt;/Column&gt;
&lt;Column field="activity" header="Activity" :headerStyle="{width:'250px'}" columnKey="activity"&gt;&lt;/Column&gt;
&lt;Column field="representative.name" header="Representative" :headerStyle="{width:'250px'}" columnKey="representative"&gt;&lt;/Column&gt;
&lt;/DataTable&gt;
&lt;/div&gt;
@ -349,7 +361,7 @@ export default {
<div class="card">
<h5>Flexible Scroll</h5>
<p>Flex scroll feature makes the scrollable viewport section dynamic so that it can grow or shrink relative to the parent size of the table.
Click the button below to display a maximizable Dialog where data viewport adjusts itself according to the size changes.</p>
click the button below to display a maximizable Dialog where data viewport adjusts itself according to the size changes.</p>
<Button label="Show" icon="pi pi-external-link" @click="openDialog" />
</div>
@ -396,14 +408,14 @@ export default {
<div class="card">
<h5>Horizontal and Vertical</h5>
<DataTable :value="customers" :scrollable="true" scrollHeight="200px" style="width: 600px" :loading="loading">
<Column field="id" header="Id" headerStyle="width: 250px" columnKey="id"></Column>
<Column field="name" header="Name" headerStyle="width: 250px" columnKey="name"></Column>
<Column field="country.name" header="Country" headerStyle="width: 250px" columnKey="country"></Column>
<Column field="date" header="Date" headerStyle="width: 250px" columnKey="date"></Column>
<Column field="company" header="Company" headerStyle="width: 250px" columnKey="company"></Column>
<Column field="status" header="Status" headerStyle="width: 250px" columnKey="status"></Column>
<Column field="activity" header="Activity" headerStyle="width: 250px" columnKey="activity"></Column>
<Column field="representative.name" header="Representative" headerStyle="width: 250px" columnKey="representative"></Column>
<Column field="id" header="Id" :headerStyle="{width:'250px'}" columnKey="id"></Column>
<Column field="name" header="Name" :headerStyle="{width:'250px'}" columnKey="name"></Column>
<Column field="country.name" header="Country" :headerStyle="{width:'250px'}" columnKey="country"></Column>
<Column field="date" header="Date" :headerStyle="{width:'250px'}" columnKey="date"></Column>
<Column field="company" header="Company" :headerStyle="{width:'250px'}" columnKey="company"></Column>
<Column field="status" header="Status" :headerStyle="{width:'250px'}" columnKey="status"></Column>
<Column field="activity" header="Activity" :headerStyle="{width:'250px'}" columnKey="activity"></Column>
<Column field="representative.name" header="Representative" :headerStyle="{width:'250px'}" columnKey="representative"></Column>
</DataTable>
</div>
@ -623,6 +635,9 @@ export default {
},
closeDialog() {
this.dialogVisible = false;
},
formatCurrency(value) {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
}
},
components: {