Fixed #338 - Scrollable TreeTable
parent
8329ed5423
commit
60547bc237
|
@ -196,6 +196,24 @@ const TreeTableProps = [
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
default: "false",
|
default: "false",
|
||||||
description: "Whether to show grid lines between cells."
|
description: "Whether to show grid lines between cells."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "scrollable",
|
||||||
|
type: "boolean",
|
||||||
|
default: "false",
|
||||||
|
description: "When specified, enables horizontal and/or vertical scrolling."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "scrollDirection",
|
||||||
|
type: "string",
|
||||||
|
default: "vertical",
|
||||||
|
description: 'Orientation of the scrolling, options are "vertical", "horizontal" and "both".'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "scrollHeight",
|
||||||
|
type: "string",
|
||||||
|
default: "null",
|
||||||
|
description: 'Height of the scroll viewport in fixed units or the "flex" keyword for a dynamic size.'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ interface DataTableProps {
|
||||||
rowClass?: any;
|
rowClass?: any;
|
||||||
scrollable?: boolean;
|
scrollable?: boolean;
|
||||||
scrollHeight?: string;
|
scrollHeight?: string;
|
||||||
|
scrollDirection?: string;
|
||||||
frozenValue?: any[];
|
frozenValue?: any[];
|
||||||
responsiveLayout?: string;
|
responsiveLayout?: string;
|
||||||
breakpoing?: string;
|
breakpoing?: string;
|
||||||
|
|
|
@ -0,0 +1,157 @@
|
||||||
|
<template>
|
||||||
|
<td :style="containerStyle" :class="containerClass">
|
||||||
|
<button type="button" class="p-treetable-toggler p-link" @click="toggle" v-if="columnProp('expander')" :style="togglerStyle" tabindex="-1" v-ripple>
|
||||||
|
<i :class="togglerIcon"></i>
|
||||||
|
</button>
|
||||||
|
<div class="p-checkbox p-treetable-checkbox p-component" @click="toggleCheckbox" v-if="checkboxSelectionMode && columnProp('expander')" role="checkbox" :aria-checked="checked">
|
||||||
|
<div class="p-hidden-accessible">
|
||||||
|
<input type="checkbox" @focus="onCheckboxFocus" @blur="onCheckboxBlur" />
|
||||||
|
</div>
|
||||||
|
<div ref="checkboxEl" :class="checkboxClass">
|
||||||
|
<span :class="checkboxIcon"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<component :is="column.children.body" :node="node" :column="column" v-if="column.children && column.children.body" />
|
||||||
|
<template v-else><span>{{resolveFieldData(node.data, columnProp('field'))}}</span></template>
|
||||||
|
</td>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {DomHandler} from 'primevue/utils';
|
||||||
|
import {ObjectUtils} from 'primevue/utils';
|
||||||
|
import Ripple from 'primevue/ripple'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'BodyCell',
|
||||||
|
emits: ['node-toggle','checkbox-toggle'],
|
||||||
|
props: {
|
||||||
|
node: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
level: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
indentation: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
leaf: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
expanded: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
selectionMode: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
checked: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
partialChecked: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
styleObject: {},
|
||||||
|
checkboxFocused: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.columnProp('frozen')) {
|
||||||
|
this.updateStickyPosition();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updated() {
|
||||||
|
if (this.columnProp('frozen')) {
|
||||||
|
this.updateStickyPosition();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggle() {
|
||||||
|
this.$emit('node-toggle', this.node);
|
||||||
|
},
|
||||||
|
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 align = this.columnProp('alignFrozen');
|
||||||
|
if (align === 'right') {
|
||||||
|
let right = 0;
|
||||||
|
let next = this.$el.nextElementSibling;
|
||||||
|
if (next) {
|
||||||
|
right = DomHandler.getOuterWidth(next) + parseFloat(next.style.right);
|
||||||
|
}
|
||||||
|
this.styleObject.right = right + 'px';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let left = 0;
|
||||||
|
let prev = this.$el.previousElementSibling;
|
||||||
|
if (prev) {
|
||||||
|
left = DomHandler.getOuterWidth(prev) + parseFloat(prev.style.left);
|
||||||
|
}
|
||||||
|
this.styleObject.left = left + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resolveFieldData(rowData, field) {
|
||||||
|
return ObjectUtils.resolveFieldData(rowData, field);
|
||||||
|
},
|
||||||
|
toggleCheckbox() {
|
||||||
|
this.$emit('checkbox-toggle');
|
||||||
|
},
|
||||||
|
onCheckboxFocus() {
|
||||||
|
this.checkboxFocused = true;
|
||||||
|
},
|
||||||
|
onCheckboxBlur() {
|
||||||
|
this.checkboxFocused = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
containerClass() {
|
||||||
|
return [this.columnProp('bodyClass'), {
|
||||||
|
'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];
|
||||||
|
},
|
||||||
|
togglerStyle() {
|
||||||
|
return {
|
||||||
|
marginLeft: this.level * this.indentation + 'rem',
|
||||||
|
visibility: this.leaf ? 'hidden' : 'visible'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
togglerIcon() {
|
||||||
|
return ['p-treetable-toggler-icon pi', {'pi-chevron-right': !this.expanded, 'pi-chevron-down': this.expanded}];
|
||||||
|
},
|
||||||
|
checkboxSelectionMode() {
|
||||||
|
return this.selectionMode === 'checkbox';
|
||||||
|
},
|
||||||
|
checkboxClass() {
|
||||||
|
return ['p-checkbox-box', {'p-highlight': this.checked, 'p-focus': this.checkboxFocused, 'p-indeterminate': this.partialChecked}];
|
||||||
|
},
|
||||||
|
checkboxIcon() {
|
||||||
|
return ['p-checkbox-icon', {'pi pi-check': this.checked, 'pi pi-minus': this.partialChecked}];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
'ripple': Ripple
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,74 @@
|
||||||
|
<template>
|
||||||
|
<td :style="containerStyle" :class="containerClass">
|
||||||
|
<component :is="column.children.footer" :column="col" v-if="column.children && column.children.footer" />
|
||||||
|
{{columnProp('footer')}}
|
||||||
|
</td>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {DomHandler} from 'primevue/utils';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'FooterCell',
|
||||||
|
props: {
|
||||||
|
column: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
styleObject: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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 align = this.columnProp('alignFrozen');
|
||||||
|
if (align === 'right') {
|
||||||
|
let right = 0;
|
||||||
|
let next = this.$el.nextElementSibling;
|
||||||
|
if (next) {
|
||||||
|
right = DomHandler.getOuterWidth(next) + parseFloat(next.style.right);
|
||||||
|
}
|
||||||
|
this.styleObject.right = right + 'px';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
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'), {
|
||||||
|
'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>
|
|
@ -0,0 +1,170 @@
|
||||||
|
<template>
|
||||||
|
<th :style="[containerStyle]" :class="containerClass" @click="onClick" @keydown="onKeyDown"
|
||||||
|
:tabindex="columnProp('sortable') ? '0' : null" :aria-sort="ariaSort">
|
||||||
|
<span class="p-column-resizer" @mousedown="onResizeStart" v-if="resizableColumns"></span>
|
||||||
|
<component :is="column.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>
|
||||||
|
</th>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {DomHandler} from 'primevue/utils';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'HeaderCell',
|
||||||
|
emits: ['column-click','column-resizestart'],
|
||||||
|
props: {
|
||||||
|
column: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
resizableColumns: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
sortField: {
|
||||||
|
type: [String, Function],
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
sortOrder: {
|
||||||
|
type: Number,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
multiSortMeta: {
|
||||||
|
type: Array,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
sortMode: {
|
||||||
|
type: String,
|
||||||
|
default: 'single'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
styleObject: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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 align = this.columnProp('alignFrozen');
|
||||||
|
if (align === 'right') {
|
||||||
|
let right = 0;
|
||||||
|
let next = this.$el.nextElementSibling;
|
||||||
|
if (next) {
|
||||||
|
right = DomHandler.getOuterWidth(next) + parseFloat(next.style.right);
|
||||||
|
}
|
||||||
|
this.styleObject.right = right + 'px';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let left = 0;
|
||||||
|
let prev = this.$el.previousElementSibling;
|
||||||
|
if (prev) {
|
||||||
|
left = DomHandler.getOuterWidth(prev) + parseFloat(prev.style.left);
|
||||||
|
}
|
||||||
|
this.styleObject.left = left + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
containerClass() {
|
||||||
|
return [this.columnProp('headerClass'), {
|
||||||
|
'p-sortable-column': this.columnProp('sortable'),
|
||||||
|
'p-resizable-column': this.resizableColumns,
|
||||||
|
'p-highlight': this.isColumnSorted(),
|
||||||
|
'p-frozen-column': this.columnProp('frozen')
|
||||||
|
}];
|
||||||
|
},
|
||||||
|
containerStyle() {
|
||||||
|
let headerStyle = 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.sortableColumnIcon;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -36,6 +36,9 @@ interface TreeTableProps {
|
||||||
columnResizeMode?: string;
|
columnResizeMode?: string;
|
||||||
indentation?: number;
|
indentation?: number;
|
||||||
showGridlines?: boolean;
|
showGridlines?: boolean;
|
||||||
|
scrollable?: boolean;
|
||||||
|
scrollHeight?: string;
|
||||||
|
scrollDirection?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare class TreeTable {
|
declare class TreeTable {
|
||||||
|
|
|
@ -22,14 +22,9 @@
|
||||||
<thead class="p-treetable-thead">
|
<thead class="p-treetable-thead">
|
||||||
<tr>
|
<tr>
|
||||||
<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">
|
||||||
<th v-if="!columnProp(col, 'hidden')" :style="[columnProp(col, 'style'),columnProp(col, 'headerStyle')]" :class="getColumnHeaderClass(col)" @click="onColumnHeaderClick($event, col)"
|
<TTHeaderCell v-if="!columnProp(col, 'hidden')" :column="col" :resizableColumns="resizableColumns"
|
||||||
:tabindex="columnProp(col, 'sortable') ? '0' : null" :aria-sort="getAriaSort(col)" @keydown="onColumnKeyDown($event, col)">
|
:sortField="d_sortField" :sortOrder="d_sortOrder" :multiSortMeta="d_multiSortMeta" :sortMode="sortMode"
|
||||||
<span class="p-column-resizer" @mousedown="onColumnResizeStart" v-if="resizableColumns"></span>
|
@column-click="onColumnHeaderClick" @column-resizestart="onColumnResizeStart"></TTHeaderCell>
|
||||||
<component :is="col.children.header" :column="col" v-if="col.children && col.children.header" />
|
|
||||||
<span class="p-column-title" v-if="columnProp(col, 'header')">{{columnProp(col, 'header')}}</span>
|
|
||||||
<span v-if="columnProp(col, 'sortable')" :class="getSortableColumnIcon(col)"></span>
|
|
||||||
<span v-if="isMultiSorted(col)" class="p-sortable-column-badge">{{getMultiSortMetaIndex(col) + 1}}</span>
|
|
||||||
</th>
|
|
||||||
</template>
|
</template>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-if="hasColumnFilter()">
|
<tr v-if="hasColumnFilter()">
|
||||||
|
@ -55,10 +50,7 @@
|
||||||
<tfoot class="p-treetable-tfoot" v-if="hasFooter">
|
<tfoot class="p-treetable-tfoot" v-if="hasFooter">
|
||||||
<tr>
|
<tr>
|
||||||
<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">
|
||||||
<td v-if="!columnProp(col, 'hidden')" :style="[columnProp(col, 'style'),columnProp(col, 'footerStyle')]" :class="getColumnFooterClass(col)">
|
<TTFooterCell v-if="!columnProp(col, 'hidden')" :column="col"></TTFooterCell>
|
||||||
<component :is="col.children.footer" :column="col" v-if="col.children && col.children.footer" />
|
|
||||||
{{columnProp(col, 'footer')}}
|
|
||||||
</td>
|
|
||||||
</template>
|
</template>
|
||||||
</tr>
|
</tr>
|
||||||
</tfoot>
|
</tfoot>
|
||||||
|
@ -84,6 +76,8 @@
|
||||||
import {ObjectUtils,DomHandler} from 'primevue/utils';
|
import {ObjectUtils,DomHandler} from 'primevue/utils';
|
||||||
import {FilterService} from 'primevue/api';
|
import {FilterService} from 'primevue/api';
|
||||||
import TreeTableRow from './TreeTableRow.vue';
|
import TreeTableRow from './TreeTableRow.vue';
|
||||||
|
import HeaderCell from './HeaderCell.vue';
|
||||||
|
import FooterCell from './FooterCell.vue';
|
||||||
import Paginator from 'primevue/paginator';
|
import Paginator from 'primevue/paginator';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -392,72 +386,15 @@ export default {
|
||||||
this.d_first = 0;
|
this.d_first = 0;
|
||||||
this.$emit('update:first', this.d_first);
|
this.$emit('update:first', this.d_first);
|
||||||
},
|
},
|
||||||
isMultiSorted(column) {
|
|
||||||
return this.columnProp(column, 'sortable') && this.getMultiSortMetaIndex(column) > -1
|
|
||||||
},
|
|
||||||
isColumnSorted(column) {
|
|
||||||
if (this.columnProp(column, 'sortable')) {
|
|
||||||
return this.sortMode === 'single' ? (this.d_sortField === (this.columnProp(column, 'field') || this.columnProp(column, 'sortField'))) : this.getMultiSortMetaIndex(column) > -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
getColumnHeaderClass(column) {
|
|
||||||
return [this.columnProp(column, 'headerClass'), {
|
|
||||||
'p-sortable-column': this.columnProp(column, 'sortable'),
|
|
||||||
'p-resizable-column': this.resizableColumns,
|
|
||||||
'p-highlight': this.isColumnSorted(column),
|
|
||||||
'p-frozen-column': this.columnProp(column, 'frozen')
|
|
||||||
}];
|
|
||||||
},
|
|
||||||
getFilterColumnHeaderClass(column) {
|
getFilterColumnHeaderClass(column) {
|
||||||
return ['p-filter-column', this.columnProp(column, 'filterHeaderClass'), {
|
return ['p-filter-column', this.columnProp(column, 'filterHeaderClass'), {
|
||||||
'p-frozen-column': this.columnProp(column, 'frozen')
|
'p-frozen-column': this.columnProp(column, 'frozen')
|
||||||
}];
|
}];
|
||||||
},
|
},
|
||||||
getColumnFooterClass(column) {
|
onColumnHeaderClick(e) {
|
||||||
return [this.columnProp(column, 'footerClass'), {
|
let event = e.originalEvent;
|
||||||
'p-frozen-column': this.columnProp(column, 'frozen')
|
let column = e.column;
|
||||||
}];
|
|
||||||
},
|
|
||||||
getSortableColumnIcon(column) {
|
|
||||||
let sorted = false;
|
|
||||||
let sortOrder = null;
|
|
||||||
|
|
||||||
if (this.sortMode === 'single') {
|
|
||||||
sorted = this.d_sortField === (this.columnProp(column, 'field')|| this.columnProp(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-alt': !sorted,
|
|
||||||
'pi-sort-amount-up-alt': sorted && sortOrder > 0,
|
|
||||||
'pi-sort-amount-down': sorted && sortOrder < 0
|
|
||||||
}
|
|
||||||
];
|
|
||||||
},
|
|
||||||
getMultiSortMetaIndex(column) {
|
|
||||||
let index = -1;
|
|
||||||
|
|
||||||
for (let i = 0; i < this.d_multiSortMeta.length; i++) {
|
|
||||||
let meta = this.d_multiSortMeta[i];
|
|
||||||
if (meta.field === (this.columnProp(column, 'field')|| this.columnProp(column, 'sortField'))) {
|
|
||||||
index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return index;
|
|
||||||
},
|
|
||||||
onColumnHeaderClick(event, column) {
|
|
||||||
if (this.columnProp(column, 'sortable')) {
|
if (this.columnProp(column, 'sortable')) {
|
||||||
const targetNode = event.target;
|
const targetNode = event.target;
|
||||||
const columnField = this.columnProp(column, 'sortField') || this.columnProp(column, 'field');
|
const columnField = this.columnProp(column, 'sortField') || this.columnProp(column, 'field');
|
||||||
|
@ -786,20 +723,6 @@ export default {
|
||||||
this.onColumnHeaderClick(event, col);
|
this.onColumnHeaderClick(event, col);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getAriaSort(column) {
|
|
||||||
if (this.columnProp(column, 'sortable')) {
|
|
||||||
const sortIcon = this.getSortableColumnIcon(column);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
hasColumnFilter() {
|
hasColumnFilter() {
|
||||||
if (this.columns) {
|
if (this.columns) {
|
||||||
for (let col of this.columns) {
|
for (let col of this.columns) {
|
||||||
|
@ -933,6 +856,8 @@ export default {
|
||||||
components: {
|
components: {
|
||||||
'TTRow': TreeTableRow,
|
'TTRow': TreeTableRow,
|
||||||
'TTPaginator': Paginator,
|
'TTPaginator': Paginator,
|
||||||
|
'TTHeaderCell': HeaderCell,
|
||||||
|
'TTFooterCell': FooterCell
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,21 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<tr :class="containerClass" @click="onClick" @keydown="onKeyDown" @touchend="onTouchEnd" :style="node.style" tabindex="0">
|
<tr :class="containerClass" @click="onClick" @keydown="onKeyDown" @touchend="onTouchEnd" :style="node.style" tabindex="0">
|
||||||
<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">
|
||||||
<td v-if="!columnProp(col, 'hidden')" :style="[columnProp(col, 'style'),columnProp(col, 'bodyStyle')]" :class="getColumnBodyClass(col)">
|
<TTBodyCell v-if="!columnProp(col, 'hidden')" :column="col" :node="node"
|
||||||
<button type="button" class="p-treetable-toggler p-link" @click="toggle" v-if="columnProp(col, 'expander')" :style="togglerStyle" tabindex="-1" v-ripple>
|
:level="level" :leaf="leaf" :indentation="indentation" :expanded="expanded" :selectionMode="selectionMode"
|
||||||
<i :class="togglerIcon"></i>
|
:checked="checked" :partialChecked="partialChecked"
|
||||||
</button>
|
@node-toggle="$emit('node-toggle', $event)" @checkbox-toggle="toggleCheckbox"></TTBodyCell>
|
||||||
<div class="p-checkbox p-treetable-checkbox p-component" @click="toggleCheckbox" v-if="checkboxSelectionMode && columnProp(col, 'expander')" role="checkbox" :aria-checked="checked">
|
|
||||||
<div class="p-hidden-accessible">
|
|
||||||
<input type="checkbox" @focus="onCheckboxFocus" @blur="onCheckboxBlur" />
|
|
||||||
</div>
|
|
||||||
<div ref="checkboxEl" :class="checkboxClass">
|
|
||||||
<span :class="checkboxIcon"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<component :is="col.children.body" :node="node" :column="col" v-if="col.children && col.children.body" />
|
|
||||||
<template v-else><span>{{resolveFieldData(node.data, columnProp(col, 'field'))}}</span></template>
|
|
||||||
</td>
|
|
||||||
</template>
|
</template>
|
||||||
</tr>
|
</tr>
|
||||||
<template v-if="expanded && node.children && node.children.length">
|
<template v-if="expanded && node.children && node.children.length">
|
||||||
|
@ -26,9 +15,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {ObjectUtils} from 'primevue/utils';
|
|
||||||
import {DomHandler} from 'primevue/utils';
|
import {DomHandler} from 'primevue/utils';
|
||||||
import Ripple from 'primevue/ripple';
|
import BodyCell from './BodyCell.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'TreeTableRow',
|
name: 'TreeTableRow',
|
||||||
|
@ -67,19 +55,11 @@ export default {
|
||||||
default: 1
|
default: 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
checkboxFocused: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
nodeTouched: false,
|
nodeTouched: false,
|
||||||
methods: {
|
methods: {
|
||||||
columnProp(col, prop) {
|
columnProp(col, prop) {
|
||||||
return col.props ? ((col.type.props[prop].type === Boolean && col.props[prop] === '') ? true : col.props[prop]) : null;
|
return col.props ? ((col.type.props[prop].type === Boolean && col.props[prop] === '') ? true : col.props[prop]) : null;
|
||||||
},
|
},
|
||||||
resolveFieldData(rowData, field) {
|
|
||||||
return ObjectUtils.resolveFieldData(rowData, field);
|
|
||||||
},
|
|
||||||
toggle() {
|
toggle() {
|
||||||
this.$emit('node-toggle', this.node);
|
this.$emit('node-toggle', this.node);
|
||||||
},
|
},
|
||||||
|
@ -207,12 +187,6 @@ export default {
|
||||||
selectionKeys: _selectionKeys
|
selectionKeys: _selectionKeys
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onCheckboxFocus() {
|
|
||||||
this.checkboxFocused = true;
|
|
||||||
},
|
|
||||||
onCheckboxBlur() {
|
|
||||||
this.checkboxFocused = false;
|
|
||||||
},
|
|
||||||
onCheckboxChange(event) {
|
onCheckboxChange(event) {
|
||||||
let check = event.check;
|
let check = event.check;
|
||||||
let _selectionKeys = {...event.selectionKeys};
|
let _selectionKeys = {...event.selectionKeys};
|
||||||
|
@ -245,12 +219,7 @@ export default {
|
||||||
check: event.check,
|
check: event.check,
|
||||||
selectionKeys: _selectionKeys
|
selectionKeys: _selectionKeys
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
getColumnBodyClass(column) {
|
|
||||||
return [this.columnProp(column, 'bodyClass'), {
|
|
||||||
'p-frozen-column': this.columnProp(column, 'frozen')
|
|
||||||
}];
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
containerClass() {
|
containerClass() {
|
||||||
|
@ -270,27 +239,9 @@ export default {
|
||||||
selected() {
|
selected() {
|
||||||
return (this.selectionMode && this.selectionKeys) ? this.selectionKeys[this.node.key] === true : false;
|
return (this.selectionMode && this.selectionKeys) ? this.selectionKeys[this.node.key] === true : false;
|
||||||
},
|
},
|
||||||
togglerIcon() {
|
|
||||||
return ['p-treetable-toggler-icon pi', {'pi-chevron-right': !this.expanded, 'pi-chevron-down': this.expanded}];
|
|
||||||
},
|
|
||||||
togglerStyle() {
|
|
||||||
return {
|
|
||||||
marginLeft: this.level * this.indentation + 'rem',
|
|
||||||
visibility: this.leaf ? 'hidden' : 'visible'
|
|
||||||
};
|
|
||||||
},
|
|
||||||
childLevel() {
|
childLevel() {
|
||||||
return this.level + 1;
|
return this.level + 1;
|
||||||
},
|
},
|
||||||
checkboxSelectionMode() {
|
|
||||||
return this.selectionMode === 'checkbox';
|
|
||||||
},
|
|
||||||
checkboxClass() {
|
|
||||||
return ['p-checkbox-box', {'p-highlight': this.checked, 'p-focus': this.checkboxFocused, 'p-indeterminate': this.partialChecked}];
|
|
||||||
},
|
|
||||||
checkboxIcon() {
|
|
||||||
return ['p-checkbox-icon', {'pi pi-check': this.checked, 'pi pi-minus': this.partialChecked}];
|
|
||||||
},
|
|
||||||
checked() {
|
checked() {
|
||||||
return this.selectionKeys ? this.selectionKeys[this.node.key] && this.selectionKeys[this.node.key].checked: false;
|
return this.selectionKeys ? this.selectionKeys[this.node.key] && this.selectionKeys[this.node.key].checked: false;
|
||||||
},
|
},
|
||||||
|
@ -298,8 +249,8 @@ export default {
|
||||||
return this.selectionKeys ? this.selectionKeys[this.node.key] && this.selectionKeys[this.node.key].partialChecked: false;
|
return this.selectionKeys ? this.selectionKeys[this.node.key] && this.selectionKeys[this.node.key].partialChecked: false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
directives: {
|
components: {
|
||||||
'ripple': Ripple
|
'TTBodyCell': BodyCell
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1047,6 +1047,84 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<h5>Scrolling</h5>
|
||||||
|
<p>TreeTable supports both horizontal and vertical scrolling with support for frozen columns. Scrollable TreeTable is enabled using <i>scrollable</i> property and <i>scrollHeight</i> to define the viewport height.</p>
|
||||||
|
<pre v-code><code><template v-pre>
|
||||||
|
<TreeTable :value="nodes" style="margin-bottom: 2rem" :scrollable="true" scrollHeight="400px">
|
||||||
|
<Column field="name" header="Name" :expander="true" style="min-width:200px"></Column>
|
||||||
|
<Column field="size" header="Size" style="min-width:200px"></Column>
|
||||||
|
<Column field="type" header="Type" style="min-width:200px"></Column>
|
||||||
|
</TreeTable>
|
||||||
|
</template>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<h5>Column Widths of a Scrollable TreeTable</h5>
|
||||||
|
<p>Scrollable treetable uses flex layout so there are a couple of rules to consider when adjusting the widths of columns.</p>
|
||||||
|
<ul>
|
||||||
|
<li>Use <i>min-width</i> in vertical scrolling only so that when there is enough space columns may grow and for smaller screens a horizontal scrollbar is displayed to provide responsive design.</li>
|
||||||
|
<li>When horizontal scrolling is enabled, prefer <i>width</i> instead of <i>min-width</i>.</li>
|
||||||
|
<li>In vertical scrolling only, use <i>flex</i> to disable grow and shrink while defining a initial width. When horizontal scrolling is enabled, this is not required as columns do not grow or shrink in horizontal scrolling.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<pre v-code><code><template v-pre>
|
||||||
|
<Column field="vin" header="Vin" style="flex: 0 0 4rem"></Column>
|
||||||
|
</template>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<h6>Flex Scroll</h6>
|
||||||
|
<p>In cases where viewport should adjust itself according to the table parent's height instead of a fixed viewport height, set scrollHeight option as flex. In example below, table is inside a Dialog where viewport size dynamically responds to the dialog size changes such as maximizing.
|
||||||
|
FlexScroll can also be used for cases where scrollable viewport should be responsive with respect to the window size for full page scroll.</p>
|
||||||
|
<pre v-code><code><template v-pre>
|
||||||
|
<Button label="Show" icon="pi pi-external-link" @click="openDialog" />
|
||||||
|
<Dialog header="Flex Scroll" v-model:visible="dialogVisible" :style="{width: '50vw'}" :maximizable="true" :modal="true" :contentStyle="{height: '300px'}">
|
||||||
|
<TreeTable :value="nodes" :scrollable="true" scrollHeight="flex">
|
||||||
|
<Column field="name" header="Name" :expander="true" style="min-width:200px"></Column>
|
||||||
|
<Column field="size" header="Size" style="min-width:200px"></Column>
|
||||||
|
<Column field="type" header="Type" style="min-width:200px"></Column>
|
||||||
|
</TreeTable>
|
||||||
|
<template #footer>
|
||||||
|
<Button label="Yes" icon="pi pi-check" @click="closeDialog" />
|
||||||
|
<Button label="No" icon="pi pi-times" @click="closeDialog" class="p-button-secondary"/>
|
||||||
|
</template>
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<h6>Horizontal Scrolling</h6>
|
||||||
|
<p>For horizontal scrolling, it is required to set <i>scrollDirection</i> to "horizontal" and give fixed widths to columns.</p>
|
||||||
|
<pre v-code><code><template v-pre>
|
||||||
|
<TreeTable :value="nodes" :scrollable="true" scrollDirection="horizontal">
|
||||||
|
<Column field="name" header="Name" :expander="true" style="width:200px"></Column>
|
||||||
|
<Column field="size" header="Size" style="width:200px"></Column>
|
||||||
|
<Column field="type" header="Type" style="width:200px"></Column>
|
||||||
|
</TreeTable>
|
||||||
|
</template>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<h6>Horizontal and Vertical Scrolling</h6>
|
||||||
|
<p>Set <i>scrollDirection</i> to "both" and give fixed widths to columns to scroll both ways.</p>
|
||||||
|
<pre v-code><code><template v-pre>
|
||||||
|
<TreeTable :value="customers" :scrollable="true" scrollHeight="400px" scrollDirection="both">
|
||||||
|
<Column field="name" header="Name" :expander="true" style="width:200px"></Column>
|
||||||
|
<Column field="size" header="Size" style="width:200px"></Column>
|
||||||
|
<Column field="type" header="Type" style="width:200px"></Column>
|
||||||
|
</TreeTable>
|
||||||
|
</template>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<h6>Frozen Columns</h6>
|
||||||
|
<p>Certain columns can be frozen by using the <i>frozen</i> property of the column component. In addition <i>alignFrozen</i> is available to define whether the column should
|
||||||
|
be fixed on the left or right.</p>
|
||||||
|
|
||||||
|
<pre v-code><code><template v-pre>
|
||||||
|
<TreeTable :value="customers" :scrollable="true" scrollHeight="400px" scrollDirection="both">
|
||||||
|
<Column field="name" header="Name" :expander="true" style="width:200px" frozen></Column>
|
||||||
|
<Column field="size" header="Size" style="width:200px"></Column>
|
||||||
|
<Column field="type" header="Type" style="width:200px" frozen alignFrozen="right"></Column>
|
||||||
|
</TreeTable>
|
||||||
|
</template>
|
||||||
</code></pre>
|
</code></pre>
|
||||||
|
|
||||||
<h5>Lazy</h5>
|
<h5>Lazy</h5>
|
||||||
|
@ -1457,6 +1535,24 @@ export default {
|
||||||
<td>boolean</td>
|
<td>boolean</td>
|
||||||
<td>false</td>
|
<td>false</td>
|
||||||
<td>Whether to show grid lines between cells.</td>
|
<td>Whether to show grid lines between cells.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>scrollable</td>
|
||||||
|
<td>boolean</td>
|
||||||
|
<td>false</td>
|
||||||
|
<td>When specified, enables horizontal and/or vertical scrolling.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>scrollDirection</td>
|
||||||
|
<td>string</td>
|
||||||
|
<td>vertical</td>
|
||||||
|
<td>Orientation of the scrolling, options are "vertical", "horizontal" and "both".</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>scrollHeight</td>
|
||||||
|
<td>string</td>
|
||||||
|
<td>null</td>
|
||||||
|
<td>Height of the scroll viewport in fixed pixels or the "flex" keyword for a dynamic size.</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -80,7 +80,7 @@
|
||||||
{{node.children ? node.children.length : 0}}
|
{{node.children ? node.children.length : 0}}
|
||||||
</template>
|
</template>
|
||||||
</Column>
|
</Column>
|
||||||
<Column header="Options" style="width:200px" alignFrozen="right" :frozen="balanceFrozen">
|
<Column header="Options" style="width:200px" alignFrozen="right" :frozen="optionsFrozen">
|
||||||
<template #body>
|
<template #body>
|
||||||
<Button type="Button" icon="pi pi-check" label="Edit Item" class="p-mr-2" style="width:100%"></Button>
|
<Button type="Button" icon="pi pi-check" label="Edit Item" class="p-mr-2" style="width:100%"></Button>
|
||||||
</template>
|
</template>
|
||||||
|
@ -109,35 +109,81 @@ export default {
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<TreeTable :value="nodes" class="p-treetable-sm" style="margin-bottom: 2rem">
|
<h5>Vertical</h5>
|
||||||
<template #header>
|
<TreeTable :value="nodes" style="margin-bottom: 2rem" :scrollable="true" scrollHeight="400px">
|
||||||
Small Table
|
<Column field="name" header="Name" :expander="true" style="min-width:200px"></Column>
|
||||||
</template>
|
<Column field="size" header="Size" style="min-width:200px"></Column>
|
||||||
<Column field="name" header="Name" :expander="true"></Column>
|
<Column field="type" header="Type" style="min-width:200px"></Column>
|
||||||
<Column field="size" header="Size"></Column>
|
|
||||||
<Column field="type" header="Type"></Column>
|
|
||||||
</TreeTable>
|
</TreeTable>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<TreeTable :value="nodes" style="margin-bottom: 2rem">
|
<h5>Flexible Scroll</h5>
|
||||||
<template #header>
|
<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.
|
||||||
Normal 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" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Dialog header="Flex Scroll" v-model:visible="dialogVisible" :style="{width: '75vw'}" :maximizable="true" :modal="true" :contentStyle="{height: '300px'}">
|
||||||
|
<TreeTable :value="nodes" :scrollable="true" scrollHeight="flex">
|
||||||
|
<Column field="name" header="Name" :expander="true" style="min-width:200px"></Column>
|
||||||
|
<Column field="size" header="Size" style="min-width:200px"></Column>
|
||||||
|
<Column field="type" header="Type" style="min-width:200px"></Column>
|
||||||
|
</TreeTable>
|
||||||
|
<template #footer>
|
||||||
|
<Button label="Ok" icon="pi pi-check" @click="closeDialog" />
|
||||||
</template>
|
</template>
|
||||||
<Column field="name" header="Name" :expander="true"></Column>
|
</Dialog>
|
||||||
<Column field="size" header="Size"></Column>
|
|
||||||
<Column field="type" header="Type"></Column>
|
<div class="card">
|
||||||
|
<h5>Horizontal and Vertical with Footer</h5>
|
||||||
|
<TreeTable :value="nodes" :scrollable="true" scrollHeight="400px" scrollDirection="both">
|
||||||
|
<Column field="name" header="Name" footer="Name" :expander="true" style="width:300px"></Column>
|
||||||
|
<Column header="Key" footer="Key" style="width:300px">
|
||||||
|
<template #body="{node}">
|
||||||
|
{{node.key}}
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
<Column field="size" header="Size" footer="Size" style="width:300px"></Column>
|
||||||
|
<Column field="type" header="Type" footer="Type" style="width:300px"></Column>
|
||||||
|
<Column header="Children" footer="Children" style="width:300px">
|
||||||
|
<template #body="{node}">
|
||||||
|
{{node.children ? node.children.length : 0}}
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
<Column header="Options" footer="Options" style="width:300px">
|
||||||
|
<template #body>
|
||||||
|
<Button type="Button" icon="pi pi-check" label="Edit" class="p-mr-2"></Button>
|
||||||
|
<Button type="Button" icon="pi pi-check" label="Delete" class="p-button-warning"></Button>
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
</TreeTable>
|
</TreeTable>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<TreeTable :value="nodes" class="p-treetable-lg" >
|
<h5>Frozen Columns</h5>
|
||||||
<template #header>
|
<ToggleButton v-model="optionsFrozen" onIcon="pi pi-lock" offIcon="pi pi-lock-open" onLabel="Unfreeze Options" offLabel="Freeze Options" style="width: 12rem" />
|
||||||
Large Table
|
|
||||||
|
<TreeTable :value="nodes" :scrollable="true" scrollHeight="400px" scrollDirection="both" class="p-mt-3">
|
||||||
|
<Column field="name" header="Name" :expander="true" style="width:300px" frozen></Column>
|
||||||
|
<Column header="Key" style="width:300px">
|
||||||
|
<template #body="{node}">
|
||||||
|
{{node.key}}
|
||||||
</template>
|
</template>
|
||||||
<Column field="name" header="Name" :expander="true"></Column>
|
</Column>
|
||||||
<Column field="size" header="Size"></Column>
|
<Column field="size" header="Size" style="width:300px"></Column>
|
||||||
<Column field="type" header="Type"></Column>
|
<Column field="type" header="Type" style="width:300px"></Column>
|
||||||
|
<Column header="Children" style="width:300px">
|
||||||
|
<template #body="{node}">
|
||||||
|
{{node.children ? node.children.length : 0}}
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
<Column header="Options" style="width:200px" alignFrozen="right" :frozen="optionsFrozen">
|
||||||
|
<template #body>
|
||||||
|
<Button type="Button" icon="pi pi-check" label="Edit Item" class="p-mr-2" style="width:100%"></Button>
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
</TreeTable>
|
</TreeTable>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -149,7 +195,9 @@ import NodeService from './service/NodeService';
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
nodes: null
|
nodes: null,
|
||||||
|
dialogVisible: false,
|
||||||
|
optionsFrozen: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
nodeService: null,
|
nodeService: null,
|
||||||
|
@ -158,6 +206,14 @@ export default {
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.nodeService.getTreeTableNodes().then(data => this.nodes = data);
|
this.nodeService.getTreeTableNodes().then(data => this.nodes = data);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
openDialog() {
|
||||||
|
this.dialogVisible = true;
|
||||||
|
},
|
||||||
|
closeDialog() {
|
||||||
|
this.dialogVisible = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<\\/script>
|
<\\/script>
|
||||||
|
@ -169,35 +225,81 @@ export default {
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<TreeTable :value="nodes" class="p-treetable-sm" style="margin-bottom: 2rem">
|
<h5>Vertical</h5>
|
||||||
<template #header>
|
<TreeTable :value="nodes" style="margin-bottom: 2rem" :scrollable="true" scrollHeight="400px">
|
||||||
Small Table
|
<Column field="name" header="Name" :expander="true" style="min-width:200px"></Column>
|
||||||
</template>
|
<Column field="size" header="Size" style="min-width:200px"></Column>
|
||||||
<Column field="name" header="Name" :expander="true"></Column>
|
<Column field="type" header="Type" style="min-width:200px"></Column>
|
||||||
<Column field="size" header="Size"></Column>
|
|
||||||
<Column field="type" header="Type"></Column>
|
|
||||||
</TreeTable>
|
</TreeTable>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<TreeTable :value="nodes" style="margin-bottom: 2rem">
|
<h5>Flexible Scroll</h5>
|
||||||
<template #header>
|
<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.
|
||||||
Normal 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" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Dialog header="Flex Scroll" v-model:visible="dialogVisible" :style="{width: '75vw'}" :maximizable="true" :modal="true" :contentStyle="{height: '300px'}">
|
||||||
|
<TreeTable :value="nodes" :scrollable="true" scrollHeight="flex">
|
||||||
|
<Column field="name" header="Name" :expander="true" style="min-width:200px"></Column>
|
||||||
|
<Column field="size" header="Size" style="min-width:200px"></Column>
|
||||||
|
<Column field="type" header="Type" style="min-width:200px"></Column>
|
||||||
|
</TreeTable>
|
||||||
|
<template #footer>
|
||||||
|
<Button label="Ok" icon="pi pi-check" @click="closeDialog" />
|
||||||
</template>
|
</template>
|
||||||
<Column field="name" header="Name" :expander="true"></Column>
|
</Dialog>
|
||||||
<Column field="size" header="Size"></Column>
|
|
||||||
<Column field="type" header="Type"></Column>
|
<div class="card">
|
||||||
|
<h5>Horizontal and Vertical with Footer</h5>
|
||||||
|
<TreeTable :value="nodes" :scrollable="true" scrollHeight="400px" scrollDirection="both">
|
||||||
|
<Column field="name" header="Name" footer="Name" :expander="true" style="width:300px"></Column>
|
||||||
|
<Column header="Key" footer="Key" style="width:300px">
|
||||||
|
<template #body="{node}">
|
||||||
|
{{node.key}}
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
<Column field="size" header="Size" footer="Size" style="width:300px"></Column>
|
||||||
|
<Column field="type" header="Type" footer="Type" style="width:300px"></Column>
|
||||||
|
<Column header="Children" footer="Children" style="width:300px">
|
||||||
|
<template #body="{node}">
|
||||||
|
{{node.children ? node.children.length : 0}}
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
<Column header="Options" footer="Options" style="width:300px">
|
||||||
|
<template #body>
|
||||||
|
<Button type="Button" icon="pi pi-check" label="Edit" class="p-mr-2"></Button>
|
||||||
|
<Button type="Button" icon="pi pi-check" label="Delete" class="p-button-warning"></Button>
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
</TreeTable>
|
</TreeTable>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<TreeTable :value="nodes" class="p-treetable-lg" >
|
<h5>Frozen Columns</h5>
|
||||||
<template #header>
|
<ToggleButton v-model="optionsFrozen" onIcon="pi pi-lock" offIcon="pi pi-lock-open" onLabel="Unfreeze Options" offLabel="Freeze Options" style="width: 12rem" />
|
||||||
Large Table
|
|
||||||
|
<TreeTable :value="nodes" :scrollable="true" scrollHeight="400px" scrollDirection="both" class="p-mt-3">
|
||||||
|
<Column field="name" header="Name" :expander="true" style="width:300px" frozen></Column>
|
||||||
|
<Column header="Key" style="width:300px">
|
||||||
|
<template #body="{node}">
|
||||||
|
{{node.key}}
|
||||||
</template>
|
</template>
|
||||||
<Column field="name" header="Name" :expander="true"></Column>
|
</Column>
|
||||||
<Column field="size" header="Size"></Column>
|
<Column field="size" header="Size" style="width:300px"></Column>
|
||||||
<Column field="type" header="Type"></Column>
|
<Column field="type" header="Type" style="width:300px"></Column>
|
||||||
|
<Column header="Children" style="width:300px">
|
||||||
|
<template #body="{node}">
|
||||||
|
{{node.children ? node.children.length : 0}}
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
<Column header="Options" style="width:200px" alignFrozen="right" :frozen="optionsFrozen">
|
||||||
|
<template #body>
|
||||||
|
<Button type="Button" icon="pi pi-check" label="Edit Item" class="p-mr-2" style="width:100%"></Button>
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
</TreeTable>
|
</TreeTable>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -215,8 +317,17 @@ export default {
|
||||||
|
|
||||||
const nodes = ref();
|
const nodes = ref();
|
||||||
const nodeService = ref(new NodeService());
|
const nodeService = ref(new NodeService());
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
const optionsFrozen = ref(false);
|
||||||
|
|
||||||
return { nodes, nodeService }
|
const openDialog = () => {
|
||||||
|
dialogVisible.value = true;
|
||||||
|
};
|
||||||
|
const closeDialog = () => {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
return { nodes, openDialog, closeDialog, dialogVisible, optionsFrozen }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<\\/script>
|
<\\/script>
|
||||||
|
@ -242,3 +353,9 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
::v-deep(.p-treetable-scrollable .p-frozen-column) {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -166,7 +166,7 @@ export default {
|
||||||
})
|
})
|
||||||
|
|
||||||
const nodes = ref();
|
const nodes = ref();
|
||||||
const nodeService = ref(new NodeService());
|
const nodeService = new NodeService();
|
||||||
|
|
||||||
return { nodes, nodeService }
|
return { nodes, nodeService }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue