Refactored Table Header into a separate component

pull/104/head
cagataycivici 2019-11-18 10:42:32 +03:00
parent 328733f5d2
commit 6ce30e39fc
6 changed files with 287 additions and 108 deletions

View File

@ -7,7 +7,6 @@
<i :class="loadingIconClass"></i> <i :class="loadingIconClass"></i>
</div> </div>
</div> </div>
<div class="p-datatable-wrapper">
<div class="p-datatable-header" v-if="$scopedSlots.header"> <div class="p-datatable-header" v-if="$scopedSlots.header">
<slot name="header"></slot> <slot name="header"></slot>
</div> </div>
@ -20,38 +19,14 @@
<slot name="paginatorRight"></slot> <slot name="paginatorRight"></slot>
</template> </template>
</DTPaginator> </DTPaginator>
<div class="p-datatable-wrapper">
<table ref="table"> <table ref="table">
<thead class="p-datatable-thead"> <DTTableHeader :columnGroup="headerColumnGroup" :columns="columns" :rowGroupMode="rowGroupMode"
<tr v-if="!headerColumnGroup"> :groupRowsBy="groupRowsBy" :resizableColumns="resizableColumns" :allRowsSelected="allRowsSelected" :empty="empty"
<template v-for="(col,i) of columns"> :sortMode="sortMode" :sortField="d_sortField" :sortOrder="d_sortOrder" :multiSortMeta="d_multiSortMeta"
<th v-if="rowGroupMode !== 'subheader' || (groupRowsBy !== col.field)" @column-click="onColumnHeaderClick($event)" @column-mousedown="onColumnHeaderMouseDown($event)"
:key="col.columnKey||col.field||i" :style="col.headerStyle" :class="getColumnHeaderClass(col)" @column-dragstart="onColumnHeaderDragStart($event)" @column-dragover="onColumnHeaderDragOver($event)" @column-dragleave="onColumnHeaderDragLeave($event)" @column-drop="onColumnHeaderDrop($event)"
@click="onColumnHeaderClick($event, col)" @mousedown="onColumnHeaderMouseDown($event, col)" @column-resizestart="onColumnResizeStart($event)" @checkbox-change="toggleRowsWithCheckbox($event)" />
@dragstart="onColumnHeaderDragStart($event)" @dragover="onColumnHeaderDragOver($event)" @dragleave="onColumnHeaderDragLeave($event)" @drop="onColumnHeaderDrop($event)"
:colspan="col.colspan" :rowspan="col.rowspan">
<span class="p-column-resizer p-clickable" @mousedown="onColumnResizeStart" v-if="resizableColumns"></span>
<ColumnSlot :column="col" type="header" v-if="col.$scopedSlots.header" />
<span class="p-column-title" v-if="col.header">{{col.header}}</span>
<span v-if="col.sortable" :class="getSortableColumnIcon(col)"></span>
<ColumnSlot :column="col" type="filter" v-if="col.$scopedSlots.filter" />
<DTHeaderCheckbox :checked="allRowsSelected" @change="toggleRowsWithCheckbox" :disabled="empty" v-if="col.selectionMode ==='multiple'" />
</th>
</template>
</tr>
<template v-else>
<tr v-for="(row,i) of headerColumnGroup.rows" :key="i">
<th v-for="(col,i) of row.columns" :key="col.columnKey||col.field||i" :style="col.headerStyle" :class="getColumnHeaderClass(col)"
@dragstart="onColumnHeaderDragStart($event)" @dragover="onColumnHeaderDragOver($event)" @dragleave="onColumnHeaderDragLeave($event)" @drop="onColumnHeaderDrop($event)"
:colspan="col.colspan" :rowspan="col.rowspan">
<ColumnSlot :column="col" type="header" v-if="col.$scopedSlots.header" />
<span class="p-column-title" v-if="col.header">{{col.header}}</span>
<span v-if="col.sortable" :class="getSortableColumnIcon(col)"></span>
<ColumnSlot :column="col" type="filter" v-if="col.$scopedSlots.filter" />
<DTHeaderCheckbox :checked="allRowsSelected" @change="toggleRowsWithCheckbox" :disabled="empty" v-if="col.selectionMode ==='multiple'" />
</th>
</tr>
</template>
</thead>
<tbody class="p-datatable-tbody"> <tbody class="p-datatable-tbody">
<template v-if="!empty"> <template v-if="!empty">
<template v-for="(rowData, index) of dataToRender"> <template v-for="(rowData, index) of dataToRender">
@ -113,6 +88,7 @@
</template> </template>
</tfoot> </tfoot>
</table> </table>
</div>
<DTPaginator v-if="paginatorBottom" :rows="d_rows" :first="d_first" :totalRecords="totalRecordsLength" :pageLinkSize="pageLinkSize" :template="paginatorTemplate" :rowsPerPageOptions="rowsPerPageOptions" <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"> :currentPageReportTemplate="currentPageReportTemplate" class="p-paginator-bottom" @page="onPage($event)" :alwaysShow="alwaysShowPaginator">
<template #left v-if="$scopedSlots.paginatorLeft"> <template #left v-if="$scopedSlots.paginatorLeft">
@ -125,7 +101,6 @@
<div class="p-datatable-footer" v-if="$scopedSlots.footer"> <div class="p-datatable-footer" v-if="$scopedSlots.footer">
<slot name="footer"></slot> <slot name="footer"></slot>
</div> </div>
</div>
<div ref="resizeHelper" class="p-column-resizer-helper p-highlight" style="display: none"></div> <div ref="resizeHelper" class="p-column-resizer-helper p-highlight" style="display: none"></div>
<span ref="reorderIndicatorUp" class="pi pi-arrow-down p-datatable-reorder-indicator-up" style="position: absolute; display: none" v-if="reorderableColumns" /> <span ref="reorderIndicatorUp" class="pi pi-arrow-down p-datatable-reorder-indicator-up" style="position: absolute; display: none" v-if="reorderableColumns" />
<span ref="reorderIndicatorDown" class="pi pi-arrow-up p-datatable-reorder-indicator-down" style="position: absolute; display: none" v-if="reorderableColumns" /> <span ref="reorderIndicatorDown" class="pi pi-arrow-up p-datatable-reorder-indicator-down" style="position: absolute; display: none" v-if="reorderableColumns" />
@ -137,9 +112,10 @@ import ObjectUtils from '../utils/ObjectUtils';
import FilterUtils from '../utils/FilterUtils'; import FilterUtils from '../utils/FilterUtils';
import DomHandler from '../utils/DomHandler'; import DomHandler from '../utils/DomHandler';
import Paginator from '../paginator/Paginator'; import Paginator from '../paginator/Paginator';
import HeaderCheckbox from './HeaderCheckbox.vue';
import ColumnSlot from './ColumnSlot.vue'; import ColumnSlot from './ColumnSlot.vue';
import BodyCell from './BodyCell.vue'; import BodyCell from './BodyCell.vue';
//import ScrollableView from './ScrollableView.vue';
import TableHeader from './TableHeader.vue';
export default { export default {
props: { props: {
@ -426,7 +402,10 @@ export default {
this.$emit('update:rows', this.d_rows); this.$emit('update:rows', this.d_rows);
this.$emit('page', event); this.$emit('page', event);
}, },
onColumnHeaderClick(event, column) { onColumnHeaderClick(e) {
const event = e.originalEvent;
const column = e.column;
if (column.sortable) { if (column.sortable) {
const targetNode = event.target; const targetNode = event.target;
const columnField = column.field || column.sortField; const columnField = column.field || column.sortField;
@ -515,51 +494,6 @@ export default {
return (this.d_multiSortMeta[index].order * result); return (this.d_multiSortMeta[index].order * result);
}, },
getMultiSortMetaIndex(column) {
let index = -1;
for (let i = 0; i < this.d_multiSortMeta.length; i++) {
let meta = this.d_multiSortMeta[i];
if (meta.field === (column.field || column.sortField)) {
index = i;
break;
}
}
return index;
},
getColumnHeaderClass(column) {
const sorted = this.sortMode === 'single' ? (this.d_sortField === (column.field || column.sortField)) : this.getMultiSortMetaIndex(column) > -1;
return [column.headerClass,
{'p-sortable-column': column.sortable},
{'p-resizable-column': this.resizableColumns},
{'p-highlight': sorted}
];
},
getSortableColumnIcon(column) {
let sorted = false;
let sortOrder = null;
if (this.sortMode === 'single') {
sorted = this.d_sortField === (column.field || column.sortField);
sortOrder = sorted ? this.d_sortOrder: 0;
}
else if (this.sortMode === 'multiple') {
let metaIndex = this.getMultiSortMetaIndex(column);
if (metaIndex > -1) {
sorted = true;
sortOrder = this.d_multiSortMeta[metaIndex].order;
}
}
return [
'p-sortable-column-icon pi pi-fw',
{'pi-sort': !sorted},
{'pi-sort-up': sorted && sortOrder > 0},
{'pi-sort-down': sorted && sortOrder < 0},
];
},
addSortMeta(meta) { addSortMeta(meta) {
let index = -1; let index = -1;
for (let i = 0; i < this.d_multiSortMeta.length; i++) { for (let i = 0; i < this.d_multiSortMeta.length; i++) {
@ -1117,8 +1051,11 @@ export default {
this.documentColumnResizeEndListener = null; this.documentColumnResizeEndListener = null;
} }
}, },
onColumnHeaderMouseDown(event, col) { onColumnHeaderMouseDown(e) {
if (this.reorderableColumns && col.reorderableColumn) { const event = e.originalEvent;
const column = e.column;
if (this.reorderableColumns && column.reorderableColumn) {
if (event.target.nodeName === 'INPUT' || event.target.nodeName === 'TEXTAREA' || DomHandler.hasClass(event.target, 'p-column-resizer')) if (event.target.nodeName === 'INPUT' || event.target.nodeName === 'TEXTAREA' || DomHandler.hasClass(event.target, 'p-column-resizer'))
event.currentTarget.draggable = false; event.currentTarget.draggable = false;
else else
@ -1784,8 +1721,9 @@ export default {
components: { components: {
'ColumnSlot': ColumnSlot, 'ColumnSlot': ColumnSlot,
'DTPaginator': Paginator, 'DTPaginator': Paginator,
'DTHeaderCheckbox': HeaderCheckbox, 'DTBodyCell': BodyCell,
'DTBodyCell': BodyCell //'DTScrollableView': ScrollableView,
'DTTableHeader': TableHeader
} }
} }
</script> </script>
@ -1972,5 +1910,4 @@ export default {
.p-datatable .p-datatable-loading-icon { .p-datatable .p-datatable-loading-icon {
font-size: 2em; font-size: 2em;
} }
</style> </style>

View File

@ -0,0 +1,14 @@
<template>
<div></div>
</template>
<script>
export default {
props: {
},
methods: {
}
}
</script>

View File

@ -0,0 +1,162 @@
<template>
<thead class="p-datatable-thead">
<tr v-if="!columnGroup">
<template v-for="(col,i) of columns">
<th v-if="rowGroupMode !== 'subheader' || (groupRowsBy !== col.field)"
:key="col.columnKey||col.field||i" :style="col.headerStyle" :class="getColumnHeaderClass(col)"
@click="onColumnHeaderClick($event, col)" @mousedown="onColumnHeaderMouseDown($event, col)"
@dragstart="onColumnHeaderDragStart($event)" @dragover="onColumnHeaderDragOver($event)" @dragleave="onColumnHeaderDragLeave($event)" @drop="onColumnHeaderDrop($event)"
:colspan="col.colspan" :rowspan="col.rowspan">
<span class="p-column-resizer p-clickable" @mousedown="onColumnResizeStart($event)" v-if="resizableColumns"></span>
<DTColumnSlot :column="col" type="header" v-if="col.$scopedSlots.header" />
<span class="p-column-title" v-if="col.header">{{col.header}}</span>
<span v-if="col.sortable" :class="getSortableColumnIcon(col)"></span>
<DTColumnSlot :column="col" type="filter" v-if="col.$scopedSlots.filter" />
<DTHeaderCheckbox :checked="allRowsSelected" @change="onHeaderCheckboxChange($event)" :disabled="empty" v-if="col.selectionMode ==='multiple'" />
</th>
</template>
</tr>
<template v-else>
<tr v-for="(row,i) of columnGroup.rows" :key="i">
<th v-for="(col,i) of row.columns" :key="col.columnKey||col.field||i" :style="col.headerStyle" :class="getColumnHeaderClass(col)"
@dragstart="onColumnHeaderDragStart($event)" @dragover="onColumnHeaderDragOver($event)" @dragleave="onColumnHeaderDragLeave($event)" @drop="onColumnHeaderDrop($event)"
:colspan="col.colspan" :rowspan="col.rowspan">
<ColumnSlot :column="col" type="header" v-if="col.$scopedSlots.header" />
<span class="p-column-title" v-if="col.header">{{col.header}}</span>
<span v-if="col.sortable" :class="getSortableColumnIcon(col)"></span>
<DTColumnSlot :column="col" type="filter" v-if="col.$scopedSlots.filter" />
<DTHeaderCheckbox :checked="allRowsSelected" @change="onHeaderCheckboxChange($event)" :disabled="empty" v-if="col.selectionMode ==='multiple'" />
</th>
</tr>
</template>
</thead>
</template>
<script>
import ColumnSlot from './ColumnSlot.vue';
import HeaderCheckbox from './HeaderCheckbox.vue';
export default {
props: {
columnGroup: {
type: null,
default: null
},
columns: {
type: null,
default: null
},
rowGroupMode: {
type: String,
default: null
},
groupRowsBy: {
type: [Array,String],
default: null
},
resizableColumns: {
type: Boolean,
default: false
},
allRowsSelected: {
type: Boolean,
default: false
},
empty: {
type: Boolean,
default: false
},
sortMode: {
type: String,
default: 'single'
},
sortField: {
type: String,
default: null
},
sortOrder: {
type: Number,
default: null
},
multiSortMeta: {
type: Array,
default: null
}
},
methods: {
getColumnHeaderClass(column) {
const sorted = this.sortMode === 'single' ? (this.sortField === (column.field || column.sortField)) : this.getMultiSortMetaIndex(column) > -1;
return [column.headerClass,
{'p-sortable-column': column.sortable},
{'p-resizable-column': this.resizableColumns},
{'p-highlight': sorted}
];
},
getSortableColumnIcon(column) {
let sorted = false;
let sortOrder = null;
if (this.sortMode === 'single') {
sorted = this.sortField === (column.field || column.sortField);
sortOrder = sorted ? this.sortOrder: 0;
}
else if (this.sortMode === 'multiple') {
let metaIndex = this.getMultiSortMetaIndex(column);
if (metaIndex > -1) {
sorted = true;
sortOrder = this.multiSortMeta[metaIndex].order;
}
}
return [
'p-sortable-column-icon pi pi-fw',
{'pi-sort': !sorted},
{'pi-sort-up': sorted && sortOrder > 0},
{'pi-sort-down': sorted && sortOrder < 0},
];
},
getMultiSortMetaIndex(column) {
let index = -1;
for (let i = 0; i < this.multiSortMeta.length; i++) {
let meta = this.multiSortMeta[i];
if (meta.field === (column.field || column.sortField)) {
index = i;
break;
}
}
return index;
},
onColumnHeaderClick(event, col) {
this.$emit('column-click', {originalEvent: event, column: col});
},
onColumnHeaderMouseDown(event, col) {
this.$emit('column-mousedown', {originalEvent: event, column: col});
},
onColumnHeaderDragStart(event) {
this.$emit('column-dragstart', event);
},
onColumnHeaderDragOver(event) {
this.$emit('column-dragover', event);
},
onColumnHeaderDragLeave(event) {
this.$emit('column-dragleave', event);
},
onColumnHeaderDrop(event) {
this.$emit('column-drop', event);
},
onColumnResizeStart(event) {
this.$emit('column-resizestart', event);
},
onHeaderCheckboxChange(event) {
this.$emit('checkbox-change', event);
}
},
components: {
'DTColumnSlot': ColumnSlot,
'DTHeaderCheckbox': HeaderCheckbox
}
}
</script>

View File

@ -201,6 +201,11 @@ export default new Router({
name: 'datatablecrud', name: 'datatablecrud',
component: () => import('./views/datatable/DataTableCrudDemo.vue') component: () => import('./views/datatable/DataTableCrudDemo.vue')
}, },
{
path: '/datatable/scroll',
name: 'datatablescroll',
component: () => import('./views/datatable/DataTableScrollDemo.vue')
},
{ {
path: '/datatable/style', path: '/datatable/style',
name: 'datatablestyle', name: 'datatablestyle',

View File

@ -0,0 +1,60 @@
<template>
<div>
<DataTableSubMenu />
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable - Scroll</h1>
<p>Data scrolling is available horizontally, vertically or both. Virtual Scrolling mode is also provided to deal with large datasets by loading data on demand during scrolling.</p>
</div>
</div>
<div class="content-section implementation">
<h3>Vertical</h3>
<DataTable :value="cars">
<Column field="vin" header="Vin"></Column>
<Column field="year" header="Year"></Column>
<Column field="brand" header="Brand"></Column>
<Column field="color" header="Color"></Column>
</DataTable>
</div>
<div class="content-section documentation">
<TabView>
<TabPanel header="Source">
<CodeHighlight>
<template v-pre>
</template>
</CodeHighlight>
<CodeHighlight lang="javascript">
</CodeHighlight>
</TabPanel>
</TabView>
</div>
</div>
</template>
<script>
import CarService from '../../service/CarService';
import DataTableSubMenu from './DataTableSubMenu';
export default {
data() {
return {
cars: null
}
},
carService: null,
created() {
this.carService = new CarService();
},
mounted() {
this.carService.getCarsLarge().then(data => this.cars = data);
},
components: {
'DataTableSubMenu': DataTableSubMenu
}
}
</script>

View File

@ -9,6 +9,7 @@
<li><router-link to="/datatable/filter">&#9679; Filter</router-link></li> <li><router-link to="/datatable/filter">&#9679; Filter</router-link></li>
<li><router-link to="/datatable/selection">&#9679; Selection</router-link></li> <li><router-link to="/datatable/selection">&#9679; Selection</router-link></li>
<li><router-link to="/datatable/lazy">&#9679; Lazy</router-link></li> <li><router-link to="/datatable/lazy">&#9679; Lazy</router-link></li>
<li><router-link to="/datatable/scroll">&#9679; Scroll</router-link></li>
<li><router-link to="/datatable/rowexpand">&#9679; Expand</router-link></li> <li><router-link to="/datatable/rowexpand">&#9679; Expand</router-link></li>
<li><router-link to="/datatable/edit">&#9679; Edit</router-link></li> <li><router-link to="/datatable/edit">&#9679; Edit</router-link></li>
<li><router-link to="/datatable/coltoggle">&#9679; ColToggle</router-link></li> <li><router-link to="/datatable/coltoggle">&#9679; ColToggle</router-link></li>