Fixed #1843 - Add virtualScroller feature to DataTable
parent
330a1119c3
commit
fa578b9673
|
@ -1,5 +1,6 @@
|
||||||
import { VNode } from 'vue';
|
import { VNode } from 'vue';
|
||||||
import { ClassComponent, GlobalComponentConstructor } from '../ts-helpers';
|
import { ClassComponent, GlobalComponentConstructor } from '../ts-helpers';
|
||||||
|
import { VirtualScrollerLoaderOptions } from '../virtualscroller';
|
||||||
|
|
||||||
type ColumnFieldType = string | ((item: any) => string) | undefined;
|
type ColumnFieldType = string | ((item: any) => string) | undefined;
|
||||||
|
|
||||||
|
@ -22,6 +23,37 @@ export interface ColumnFilterMatchModeOptions {
|
||||||
[key: string]: string;
|
[key: string]: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ColumnLoadingOptions extends VirtualScrollerLoaderOptions {
|
||||||
|
/**
|
||||||
|
* Cell index
|
||||||
|
*/
|
||||||
|
cellIndex: number;
|
||||||
|
/**
|
||||||
|
* Whether the cell is first.
|
||||||
|
*/
|
||||||
|
cellFirst: boolean;
|
||||||
|
/**
|
||||||
|
* Whether the cell is last.
|
||||||
|
*/
|
||||||
|
cellLast: boolean;
|
||||||
|
/**
|
||||||
|
* Whether the cell is even.
|
||||||
|
*/
|
||||||
|
cellEven: boolean;
|
||||||
|
/**
|
||||||
|
* Whether the item is odd.
|
||||||
|
*/
|
||||||
|
cellOdd: boolean;
|
||||||
|
/**
|
||||||
|
* Column instance
|
||||||
|
*/
|
||||||
|
column: Column;
|
||||||
|
/**
|
||||||
|
* Column field
|
||||||
|
*/
|
||||||
|
field: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ColumnProps {
|
export interface ColumnProps {
|
||||||
/**
|
/**
|
||||||
* Identifier of a column if field property is not defined.
|
* Identifier of a column if field property is not defined.
|
||||||
|
@ -375,6 +407,37 @@ export interface ColumnSlots {
|
||||||
*/
|
*/
|
||||||
filterCallback: () => void;
|
filterCallback: () => void;
|
||||||
}) => VNode[];
|
}) => VNode[];
|
||||||
|
/**
|
||||||
|
* Custom loading template.
|
||||||
|
* @param {Object} scope - loading slot's params.
|
||||||
|
*/
|
||||||
|
loading: (scope: {
|
||||||
|
/**
|
||||||
|
* Row data.
|
||||||
|
*/
|
||||||
|
data: any;
|
||||||
|
/**
|
||||||
|
* Column node.
|
||||||
|
*/
|
||||||
|
column: Column;
|
||||||
|
/**
|
||||||
|
* Column field.
|
||||||
|
*/
|
||||||
|
field: string;
|
||||||
|
/**
|
||||||
|
* Row index.
|
||||||
|
*/
|
||||||
|
index: number;
|
||||||
|
/**
|
||||||
|
* Whether the row is frozen.
|
||||||
|
*/
|
||||||
|
frozenRow: boolean;
|
||||||
|
/**
|
||||||
|
* Loading options.
|
||||||
|
* @see ColumnLoadingOptions
|
||||||
|
*/
|
||||||
|
loadingOptions: ColumnLoadingOptions;
|
||||||
|
}) => VNode[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare type ColumnEmits = {
|
export declare type ColumnEmits = {
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<td :style="containerStyle" :class="containerClass" @click="onClick" @keydown="onKeyDown" role="cell">
|
<td v-if="loading" :style="containerStyle" :class="containerClass">
|
||||||
|
<component :is="column.children.loading" :data="rowData" :column="column" :field="field" :index="rowIndex" :frozenRow="frozenRow" :loadingOptions="loadingOptions" />
|
||||||
|
</td>
|
||||||
|
<td v-else :style="containerStyle" :class="containerClass" @click="onClick" @keydown="onKeyDown" role="cell">
|
||||||
<span v-if="responsiveLayout === 'stack'" class="p-column-title">{{columnProp('header')}}</span>
|
<span v-if="responsiveLayout === 'stack'" class="p-column-title">{{columnProp('header')}}</span>
|
||||||
<component :is="column.children.body" :data="rowData" :column="column" :field="field" :index="rowIndex" :frozenRow="frozenRow" v-if="column.children && column.children.body && !d_editing" />
|
<component :is="column.children.body" :data="rowData" :column="column" :field="field" :index="rowIndex" :frozenRow="frozenRow" v-if="column.children && column.children.body && !d_editing" />
|
||||||
<component :is="column.children.editor" :data="editingRowData" :column="column" :field="field" :index="rowIndex" :frozenRow="frozenRow" v-else-if="column.children && column.children.editor && d_editing" />
|
<component :is="column.children.editor" :data="editingRowData" :column="column" :field="field" :index="rowIndex" :frozenRow="frozenRow" v-else-if="column.children && column.children.editor && d_editing" />
|
||||||
|
@ -86,6 +89,10 @@ export default {
|
||||||
responsiveLayout: {
|
responsiveLayout: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'stack'
|
default: 'stack'
|
||||||
|
},
|
||||||
|
virtualScrollerContentProps: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
documentEditListener: null,
|
documentEditListener: null,
|
||||||
|
@ -339,6 +346,9 @@ export default {
|
||||||
this.styleObject.left = left + 'px';
|
this.styleObject.left = left + 'px';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
getVirtualScrollerProp(option) {
|
||||||
|
return this.virtualScrollerContentProps ? this.virtualScrollerContentProps[option] : null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -361,6 +371,21 @@ export default {
|
||||||
let columnStyle = this.columnProp('style');
|
let columnStyle = this.columnProp('style');
|
||||||
|
|
||||||
return this.columnProp('frozen') ? [columnStyle, bodyStyle, this.styleObject]: [columnStyle, bodyStyle];
|
return this.columnProp('frozen') ? [columnStyle, bodyStyle, this.styleObject]: [columnStyle, bodyStyle];
|
||||||
|
},
|
||||||
|
loading() {
|
||||||
|
return this.getVirtualScrollerProp('loading');
|
||||||
|
},
|
||||||
|
loadingOptions() {
|
||||||
|
const getLoaderOptions = this.getVirtualScrollerProp('getLoaderOptions');
|
||||||
|
return getLoaderOptions && getLoaderOptions(this.rowIndex, {
|
||||||
|
cellIndex: this.index,
|
||||||
|
cellFirst: this.index === 0,
|
||||||
|
cellLast: this.index === (this.getVirtualScrollerProp('columns').length - 1),
|
||||||
|
cellEven: this.index % 2 === 0,
|
||||||
|
cellOdd: this.index % 2 !== 0,
|
||||||
|
column: this.column,
|
||||||
|
field: this.field
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -16,15 +16,17 @@
|
||||||
<slot name="paginatorend"></slot>
|
<slot name="paginatorend"></slot>
|
||||||
</template>
|
</template>
|
||||||
</DTPaginator>
|
</DTPaginator>
|
||||||
<div class="p-datatable-wrapper" :style="{maxHeight: scrollHeight}">
|
<div class="p-datatable-wrapper" :style="{ maxHeight: virtualScrollerDisabled ? scrollHeight : '' }">
|
||||||
<table ref="table" role="table" :class="[tableClass, 'p-datatable-table']" :style="tableStyle">
|
<DTVirtualScroller v-bind="virtualScrollerOptions" :items="processedData" :columns="columns" :style="{ height: scrollHeight }" :disabled="virtualScrollerDisabled" loaderDisabled :showSpacer="false">
|
||||||
<DTTableHeader :columnGroup="headerColumnGroup" :columns="columns" :rowGroupMode="rowGroupMode"
|
<template #content="slotProps">
|
||||||
|
<table ref="table" role="table" :class="[tableClass, 'p-datatable-table']" :style="[tableStyle, slotProps.spacerStyle]">
|
||||||
|
<DTTableHeader :columnGroup="headerColumnGroup" :columns="slotProps.columns" :rowGroupMode="rowGroupMode"
|
||||||
:groupRowsBy="groupRowsBy" :groupRowSortField="groupRowSortField" :resizableColumns="resizableColumns" :allRowsSelected="allRowsSelected" :empty="empty"
|
:groupRowsBy="groupRowsBy" :groupRowSortField="groupRowSortField" :resizableColumns="resizableColumns" :allRowsSelected="allRowsSelected" :empty="empty"
|
||||||
:sortMode="sortMode" :sortField="d_sortField" :sortOrder="d_sortOrder" :multiSortMeta="d_multiSortMeta" :filters="d_filters" :filtersStore="filters" :filterDisplay="filterDisplay"
|
: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-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-dragstart="onColumnHeaderDragStart($event)" @column-dragover="onColumnHeaderDragOver($event)" @column-dragleave="onColumnHeaderDragLeave($event)" @column-drop="onColumnHeaderDrop($event)"
|
||||||
@column-resizestart="onColumnResizeStart($event)" @checkbox-change="toggleRowsWithCheckbox($event)" />
|
@column-resizestart="onColumnResizeStart($event)" @checkbox-change="toggleRowsWithCheckbox($event)" />
|
||||||
<DTTableBody v-if="frozenValue" :value="frozenValue" :frozenRow="true" class="p-datatable-frozen-tbody" :columns="columns" :dataKey="dataKey" :selection="selection" :selectionKeys="d_selectionKeys" :selectionMode="selectionMode" :contextMenu="contextMenu" :contextMenuSelection="contextMenuSelection"
|
<DTTableBody v-if="frozenValue" :value="frozenValue" :frozenRow="true" class="p-datatable-frozen-tbody" :columns="slotProps.columns" :dataKey="dataKey" :selection="selection" :selectionKeys="d_selectionKeys" :selectionMode="selectionMode" :contextMenu="contextMenu" :contextMenuSelection="contextMenuSelection"
|
||||||
:rowGroupMode="rowGroupMode" :groupRowsBy="groupRowsBy" :expandableRowGroups="expandableRowGroups" :rowClass="rowClass" :rowStyle="rowStyle" :editMode="editMode" :compareSelectionBy="compareSelectionBy" :scrollable="scrollable"
|
:rowGroupMode="rowGroupMode" :groupRowsBy="groupRowsBy" :expandableRowGroups="expandableRowGroups" :rowClass="rowClass" :rowStyle="rowStyle" :editMode="editMode" :compareSelectionBy="compareSelectionBy" :scrollable="scrollable"
|
||||||
:expandedRowIcon="expandedRowIcon" :collapsedRowIcon="collapsedRowIcon" :expandedRows="expandedRows" :expandedRowKeys="d_expandedRowKeys" :expandedRowGroups="expandedRowGroups"
|
:expandedRowIcon="expandedRowIcon" :collapsedRowIcon="collapsedRowIcon" :expandedRows="expandedRows" :expandedRowKeys="d_expandedRowKeys" :expandedRowGroups="expandedRowGroups"
|
||||||
:editingRows="editingRows" :editingRowKeys="d_editingRowKeys" :templates="$slots" :loading="loading" :responsiveLayout="responsiveLayout"
|
:editingRows="editingRows" :editingRowKeys="d_editingRowKeys" :templates="$slots" :loading="loading" :responsiveLayout="responsiveLayout"
|
||||||
|
@ -33,8 +35,8 @@
|
||||||
@row-toggle="toggleRow($event)" @radio-change="toggleRowWithRadio($event)" @checkbox-change="toggleRowWithCheckbox($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)"
|
@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)"
|
@row-edit-init="onRowEditInit($event)" @row-edit-save="onRowEditSave($event)" @row-edit-cancel="onRowEditCancel($event)"
|
||||||
:editingMeta="d_editingMeta" @editing-meta-change="onEditingMetaChange" />
|
:editingMeta="d_editingMeta" @editing-meta-change="onEditingMetaChange" :isVirtualScrollerDisabled="true" />
|
||||||
<DTTableBody :value="dataToRender" :columns="columns" :empty="empty" :dataKey="dataKey" :selection="selection" :selectionKeys="d_selectionKeys" :selectionMode="selectionMode" :contextMenu="contextMenu" :contextMenuSelection="contextMenuSelection"
|
<DTTableBody :value="dataToRender(slotProps.rows)" :class="slotProps.styleClass" :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" :rowStyle="rowStyle" :editMode="editMode" :compareSelectionBy="compareSelectionBy" :scrollable="scrollable"
|
:rowGroupMode="rowGroupMode" :groupRowsBy="groupRowsBy" :expandableRowGroups="expandableRowGroups" :rowClass="rowClass" :rowStyle="rowStyle" :editMode="editMode" :compareSelectionBy="compareSelectionBy" :scrollable="scrollable"
|
||||||
:expandedRowIcon="expandedRowIcon" :collapsedRowIcon="collapsedRowIcon" :expandedRows="expandedRows" :expandedRowKeys="d_expandedRowKeys" :expandedRowGroups="expandedRowGroups"
|
:expandedRowIcon="expandedRowIcon" :collapsedRowIcon="collapsedRowIcon" :expandedRows="expandedRows" :expandedRowKeys="d_expandedRowKeys" :expandedRowGroups="expandedRowGroups"
|
||||||
:editingRows="editingRows" :editingRowKeys="d_editingRowKeys" :templates="$slots" :loading="loading" :responsiveLayout="responsiveLayout"
|
:editingRows="editingRows" :editingRowKeys="d_editingRowKeys" :templates="$slots" :loading="loading" :responsiveLayout="responsiveLayout"
|
||||||
|
@ -43,9 +45,12 @@
|
||||||
@row-toggle="toggleRow($event)" @radio-change="toggleRowWithRadio($event)" @checkbox-change="toggleRowWithCheckbox($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)"
|
@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)"
|
@row-edit-init="onRowEditInit($event)" @row-edit-save="onRowEditSave($event)" @row-edit-cancel="onRowEditCancel($event)"
|
||||||
:editingMeta="d_editingMeta" @editing-meta-change="onEditingMetaChange" />
|
:editingMeta="d_editingMeta" @editing-meta-change="onEditingMetaChange"
|
||||||
<DTTableFooter :columnGroup="footerColumnGroup" :columns="columns" />
|
:virtualScrollerContentProps="slotProps" :isVirtualScrollerDisabled="virtualScrollerDisabled" />
|
||||||
|
<DTTableFooter :columnGroup="footerColumnGroup" :columns="slotProps.columns" />
|
||||||
</table>
|
</table>
|
||||||
|
</template>
|
||||||
|
</DTVirtualScroller>
|
||||||
</div>
|
</div>
|
||||||
<DTPaginator v-if="paginatorBottom" :rows="d_rows" :first="lazy ? 0 : d_first" :totalRecords="totalRecordsLength" :pageLinkSize="pageLinkSize" :template="paginatorTemplate" :rowsPerPageOptions="rowsPerPageOptions"
|
<DTPaginator v-if="paginatorBottom" :rows="d_rows" :first="lazy ? 0 : d_first" :totalRecords="totalRecordsLength" :pageLinkSize="pageLinkSize" :template="paginatorTemplate" :rowsPerPageOptions="rowsPerPageOptions"
|
||||||
:currentPageReportTemplate="currentPageReportTemplate" class="p-paginator-bottom" @page="onPage($event)" :alwaysShow="alwaysShowPaginator">
|
:currentPageReportTemplate="currentPageReportTemplate" class="p-paginator-bottom" @page="onPage($event)" :alwaysShow="alwaysShowPaginator">
|
||||||
|
@ -69,6 +74,7 @@
|
||||||
import {ObjectUtils,DomHandler,UniqueComponentId} from 'primevue/utils';
|
import {ObjectUtils,DomHandler,UniqueComponentId} from 'primevue/utils';
|
||||||
import {FilterMatchMode,FilterOperator,FilterService} from 'primevue/api';
|
import {FilterMatchMode,FilterOperator,FilterService} from 'primevue/api';
|
||||||
import Paginator from 'primevue/paginator';
|
import Paginator from 'primevue/paginator';
|
||||||
|
import VirtualScroller from 'primevue/virtualscroller';
|
||||||
import TableHeader from './TableHeader.vue';
|
import TableHeader from './TableHeader.vue';
|
||||||
import TableBody from './TableBody.vue';
|
import TableBody from './TableBody.vue';
|
||||||
import TableFooter from './TableFooter.vue';
|
import TableFooter from './TableFooter.vue';
|
||||||
|
@ -297,6 +303,10 @@ export default {
|
||||||
type: String,
|
type: String,
|
||||||
default: "vertical"
|
default: "vertical"
|
||||||
},
|
},
|
||||||
|
virtualScrollerOptions: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
scrollHeight: {
|
scrollHeight: {
|
||||||
type: String,
|
type: String,
|
||||||
default: null
|
default: null
|
||||||
|
@ -1766,6 +1776,16 @@ export default {
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
},
|
},
|
||||||
|
dataToRender(data) {
|
||||||
|
const _data = data || this.processedData;
|
||||||
|
|
||||||
|
if (_data && this.paginator) {
|
||||||
|
const first = this.lazy ? 0 : this.d_first;
|
||||||
|
return _data.slice(first, first + this.d_rows);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
containerClass() {
|
containerClass() {
|
||||||
|
@ -1859,17 +1879,6 @@ export default {
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
dataToRender() {
|
|
||||||
const data = this.processedData;
|
|
||||||
|
|
||||||
if (data && this.paginator) {
|
|
||||||
const first = this.lazy ? 0 : this.d_first;
|
|
||||||
return data.slice(first, first + this.d_rows);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
totalRecordsLength() {
|
totalRecordsLength() {
|
||||||
if (this.lazy) {
|
if (this.lazy) {
|
||||||
return this.totalRecords;
|
return this.totalRecords;
|
||||||
|
@ -1905,6 +1914,9 @@ export default {
|
||||||
},
|
},
|
||||||
groupRowSortField() {
|
groupRowSortField() {
|
||||||
return this.sortMode === 'single' ? this.sortField : (this.d_groupRowsSortMeta ? this.d_groupRowsSortMeta.field : null);
|
return this.sortMode === 'single' ? this.sortField : (this.d_groupRowsSortMeta ? this.d_groupRowsSortMeta.field : null);
|
||||||
|
},
|
||||||
|
virtualScrollerDisabled() {
|
||||||
|
return ObjectUtils.isEmpty(this.virtualScrollerOptions) || !this.scrollable;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
@ -1912,6 +1924,7 @@ export default {
|
||||||
'DTTableHeader': TableHeader,
|
'DTTableHeader': TableHeader,
|
||||||
'DTTableBody': TableBody,
|
'DTTableBody': TableBody,
|
||||||
'DTTableFooter': TableFooter,
|
'DTTableFooter': TableFooter,
|
||||||
|
'DTVirtualScroller': VirtualScroller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -2205,4 +2218,13 @@ export default {
|
||||||
.p-datatable .p-datatable-tbody > tr > td > .p-column-title {
|
.p-datatable .p-datatable-tbody > tr > td > .p-column-title {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* VirtualScroller */
|
||||||
|
.p-datatable .p-virtualscroller-loading {
|
||||||
|
transform: none !important;
|
||||||
|
min-height: 0;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,37 +1,37 @@
|
||||||
<template>
|
<template>
|
||||||
<tbody class="p-datatable-tbody" role="rowgroup">
|
<tbody :ref="bodyRef" class="p-datatable-tbody" role="rowgroup" :style="bodyStyle">
|
||||||
<template v-if="!empty">
|
<template v-if="!empty">
|
||||||
<template v-for="(rowData, index) of value" :key="getRowKey(rowData, index) + '_subheader'">
|
<template v-for="(rowData, index) of value" :key="getRowKey(rowData, getRowIndex(index)) + '_subheader'">
|
||||||
<tr class="p-rowgroup-header" :style="rowGroupHeaderStyle" v-if="templates['groupheader'] && rowGroupMode === 'subheader' && shouldRenderRowGroupHeader(value, rowData, index)" role="row">
|
<tr class="p-rowgroup-header" :style="rowGroupHeaderStyle" v-if="templates['groupheader'] && rowGroupMode === 'subheader' && shouldRenderRowGroupHeader(value, rowData, getRowIndex(index))" role="row">
|
||||||
<td :colspan="columnsLength - 1">
|
<td :colspan="columnsLength - 1">
|
||||||
<button class="p-row-toggler p-link" @click="onRowGroupToggle($event, rowData)" v-if="expandableRowGroups" type="button">
|
<button class="p-row-toggler p-link" @click="onRowGroupToggle($event, rowData)" v-if="expandableRowGroups" type="button">
|
||||||
<span :class="rowGroupTogglerIcon(rowData)"></span>
|
<span :class="rowGroupTogglerIcon(rowData)"></span>
|
||||||
</button>
|
</button>
|
||||||
<component :is="templates['groupheader']" :data="rowData" :index="index" />
|
<component :is="templates['groupheader']" :data="rowData" :index="getRowIndex(index)" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr :class="getRowClass(rowData)" :style="rowStyle" :key="getRowKey(rowData, index)"
|
<tr :class="getRowClass(rowData)" :style="rowStyle" :key="getRowKey(rowData, getRowIndex(index))"
|
||||||
v-if="expandableRowGroups ? isRowGroupExpanded(rowData): true"
|
v-if="expandableRowGroups ? isRowGroupExpanded(rowData): true"
|
||||||
@click="onRowClick($event, rowData, index)" @dblclick="onRowDblClick($event, rowData, index)" @contextmenu="onRowRightClick($event, rowData, index)" @touchend="onRowTouchEnd($event)" @keydown="onRowKeyDown($event, rowData, index)" :tabindex="selectionMode || contextMenu ? '0' : null"
|
@click="onRowClick($event, rowData, getRowIndex(index))" @dblclick="onRowDblClick($event, rowData, getRowIndex(index))" @contextmenu="onRowRightClick($event, rowData, getRowIndex(index))" @touchend="onRowTouchEnd($event)" @keydown="onRowKeyDown($event, rowData, getRowIndex(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)" role="row">
|
@mousedown="onRowMouseDown($event)" @dragstart="onRowDragStart($event, getRowIndex(index))" @dragover="onRowDragOver($event, getRowIndex(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">
|
<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" :rowIndex="index" :index="i" :selected="isSelected(rowData)"
|
<DTBodyCell v-if="shouldRenderBodyCell(value, col, getRowIndex(index))" :rowData="rowData" :column="col" :rowIndex="getRowIndex(index)" :index="i" :selected="isSelected(rowData)"
|
||||||
:rowTogglerIcon="columnProp(col,'expander') ? rowTogglerIcon(rowData): null" :frozenRow="frozenRow"
|
:rowTogglerIcon="columnProp(col,'expander') ? rowTogglerIcon(rowData): null" :frozenRow="frozenRow"
|
||||||
:rowspan="rowGroupMode === 'rowspan' ? calculateRowGroupSize(value, col, index) : null"
|
:rowspan="rowGroupMode === 'rowspan' ? calculateRowGroupSize(value, col, getRowIndex(index)) : null"
|
||||||
:editMode="editMode" :editing="editMode === 'row' && isRowEditing(rowData)" :responsiveLayout="responsiveLayout"
|
:editMode="editMode" :editing="editMode === 'row' && isRowEditing(rowData)" :responsiveLayout="responsiveLayout"
|
||||||
@radio-change="onRadioChange($event)" @checkbox-change="onCheckboxChange($event)" @row-toggle="onRowToggle($event)"
|
@radio-change="onRadioChange($event)" @checkbox-change="onCheckboxChange($event)" @row-toggle="onRowToggle($event)"
|
||||||
@cell-edit-init="onCellEditInit($event)" @cell-edit-complete="onCellEditComplete($event)" @cell-edit-cancel="onCellEditCancel($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)"
|
@row-edit-init="onRowEditInit($event)" @row-edit-save="onRowEditSave($event)" @row-edit-cancel="onRowEditCancel($event)"
|
||||||
:editingMeta="editingMeta" @editing-meta-change="onEditingMetaChange"/>
|
:editingMeta="editingMeta" @editing-meta-change="onEditingMetaChange" :virtualScrollerContentProps="virtualScrollerContentProps"/>
|
||||||
</template>
|
</template>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="p-datatable-row-expansion" v-if="templates['expansion'] && expandedRows && isRowExpanded(rowData)" :key="getRowKey(rowData, index) + '_expansion'" role="row">
|
<tr class="p-datatable-row-expansion" v-if="templates['expansion'] && expandedRows && isRowExpanded(rowData)" :key="getRowKey(rowData, getRowIndex(index)) + '_expansion'" role="row">
|
||||||
<td :colspan="columnsLength">
|
<td :colspan="columnsLength">
|
||||||
<component :is="templates['expansion']" :data="rowData" :index="index" />
|
<component :is="templates['expansion']" :data="rowData" :index="getRowIndex(index)" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="p-rowgroup-footer" v-if="templates['groupfooter'] && rowGroupMode === 'subheader' && shouldRenderRowGroupFooter(value, rowData, index)" :key="getRowKey(rowData, index) + '_subfooter'" role="row">
|
<tr class="p-rowgroup-footer" v-if="templates['groupfooter'] && rowGroupMode === 'subheader' && shouldRenderRowGroupFooter(value, rowData, getRowIndex(index))" :key="getRowKey(rowData, getRowIndex(index)) + '_subfooter'" role="row">
|
||||||
<component :is="templates['groupfooter']" :data="rowData" :index="index" />
|
<component :is="templates['groupfooter']" :data="rowData" :index="getRowIndex(index)" />
|
||||||
</tr>
|
</tr>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
@ -170,6 +170,21 @@ export default {
|
||||||
responsiveLayout: {
|
responsiveLayout: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'stack'
|
default: 'stack'
|
||||||
|
},
|
||||||
|
virtualScrollerContentProps: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
isVirtualScrollerDisabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
virtualScrollerContentProps(newValue, oldValue) {
|
||||||
|
if (!this.isVirtualScrollerDisabled && this.getVirtualScrollerProp('vertical') && this.getVirtualScrollerProp('itemSize', oldValue) !== this.getVirtualScrollerProp('itemSize', newValue)) {
|
||||||
|
this.updateVirtualScrollerPosition();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -180,6 +195,10 @@ export default {
|
||||||
if (this.scrollable && this.rowGroupMode === 'subheader') {
|
if (this.scrollable && this.rowGroupMode === 'subheader') {
|
||||||
this.updateFrozenRowGroupHeaderStickyPosition();
|
this.updateFrozenRowGroupHeaderStickyPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.isVirtualScrollerDisabled && this.getVirtualScrollerProp('vertical')) {
|
||||||
|
this.updateVirtualScrollerPosition();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
updated() {
|
updated() {
|
||||||
if (this.frozenRow) {
|
if (this.frozenRow) {
|
||||||
|
@ -213,6 +232,10 @@ export default {
|
||||||
getRowKey(rowData, index) {
|
getRowKey(rowData, index) {
|
||||||
return this.dataKey ? ObjectUtils.resolveFieldData(rowData, this.dataKey): index;
|
return this.dataKey ? ObjectUtils.resolveFieldData(rowData, this.dataKey): index;
|
||||||
},
|
},
|
||||||
|
getRowIndex(index) {
|
||||||
|
const getItemOptions = this.getVirtualScrollerProp('getItemOptions');
|
||||||
|
return getItemOptions ? getItemOptions(index).index : index;
|
||||||
|
},
|
||||||
getRowClass(rowData) {
|
getRowClass(rowData) {
|
||||||
let rowStyleClass = [];
|
let rowStyleClass = [];
|
||||||
if (this.selectionMode) {
|
if (this.selectionMode) {
|
||||||
|
@ -465,6 +488,19 @@ export default {
|
||||||
updateFrozenRowGroupHeaderStickyPosition() {
|
updateFrozenRowGroupHeaderStickyPosition() {
|
||||||
let tableHeaderHeight = DomHandler.getOuterHeight(this.$el.previousElementSibling);
|
let tableHeaderHeight = DomHandler.getOuterHeight(this.$el.previousElementSibling);
|
||||||
this.rowGroupHeaderStyleObject.top = tableHeaderHeight + 'px'
|
this.rowGroupHeaderStyleObject.top = tableHeaderHeight + 'px'
|
||||||
|
},
|
||||||
|
updateVirtualScrollerPosition() {
|
||||||
|
const tableHeaderHeight = DomHandler.getOuterHeight(this.$el.previousElementSibling);
|
||||||
|
this.$el.style.top = (this.$el.style.top || 0) + tableHeaderHeight + 'px';
|
||||||
|
},
|
||||||
|
getVirtualScrollerProp(option, options) {
|
||||||
|
options = options || this.virtualScrollerContentProps;
|
||||||
|
return options ? options[option] : null;
|
||||||
|
},
|
||||||
|
bodyRef(el) {
|
||||||
|
// For VirtualScroller
|
||||||
|
const contentRef = this.getVirtualScrollerProp('contentRef');
|
||||||
|
contentRef && contentRef(el);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -477,6 +513,9 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
},
|
||||||
|
bodyStyle() {
|
||||||
|
return this.getVirtualScrollerProp('contentStyle');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
Loading…
Reference in New Issue