Fixed #338 - Scrollable TreeTable
parent
8329ed5423
commit
60547bc237
|
@ -196,6 +196,24 @@ const TreeTableProps = [
|
|||
type: "boolean",
|
||||
default: "false",
|
||||
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;
|
||||
scrollable?: boolean;
|
||||
scrollHeight?: string;
|
||||
scrollDirection?: string;
|
||||
frozenValue?: any[];
|
||||
responsiveLayout?: 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;
|
||||
indentation?: number;
|
||||
showGridlines?: boolean;
|
||||
scrollable?: boolean;
|
||||
scrollHeight?: string;
|
||||
scrollDirection?: string;
|
||||
}
|
||||
|
||||
declare class TreeTable {
|
||||
|
|
|
@ -22,14 +22,9 @@
|
|||
<thead class="p-treetable-thead">
|
||||
<tr>
|
||||
<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)"
|
||||
:tabindex="columnProp(col, 'sortable') ? '0' : null" :aria-sort="getAriaSort(col)" @keydown="onColumnKeyDown($event, col)">
|
||||
<span class="p-column-resizer" @mousedown="onColumnResizeStart" v-if="resizableColumns"></span>
|
||||
<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>
|
||||
<TTHeaderCell v-if="!columnProp(col, 'hidden')" :column="col" :resizableColumns="resizableColumns"
|
||||
:sortField="d_sortField" :sortOrder="d_sortOrder" :multiSortMeta="d_multiSortMeta" :sortMode="sortMode"
|
||||
@column-click="onColumnHeaderClick" @column-resizestart="onColumnResizeStart"></TTHeaderCell>
|
||||
</template>
|
||||
</tr>
|
||||
<tr v-if="hasColumnFilter()">
|
||||
|
@ -55,10 +50,7 @@
|
|||
<tfoot class="p-treetable-tfoot" v-if="hasFooter">
|
||||
<tr>
|
||||
<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)">
|
||||
<component :is="col.children.footer" :column="col" v-if="col.children && col.children.footer" />
|
||||
{{columnProp(col, 'footer')}}
|
||||
</td>
|
||||
<TTFooterCell v-if="!columnProp(col, 'hidden')" :column="col"></TTFooterCell>
|
||||
</template>
|
||||
</tr>
|
||||
</tfoot>
|
||||
|
@ -84,6 +76,8 @@
|
|||
import {ObjectUtils,DomHandler} from 'primevue/utils';
|
||||
import {FilterService} from 'primevue/api';
|
||||
import TreeTableRow from './TreeTableRow.vue';
|
||||
import HeaderCell from './HeaderCell.vue';
|
||||
import FooterCell from './FooterCell.vue';
|
||||
import Paginator from 'primevue/paginator';
|
||||
|
||||
export default {
|
||||
|
@ -392,72 +386,15 @@ export default {
|
|||
this.d_first = 0;
|
||||
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) {
|
||||
return ['p-filter-column', this.columnProp(column, 'filterHeaderClass'), {
|
||||
'p-frozen-column': this.columnProp(column, 'frozen')
|
||||
}];
|
||||
},
|
||||
getColumnFooterClass(column) {
|
||||
return [this.columnProp(column, 'footerClass'), {
|
||||
'p-frozen-column': this.columnProp(column, 'frozen')
|
||||
}];
|
||||
},
|
||||
getSortableColumnIcon(column) {
|
||||
let sorted = false;
|
||||
let sortOrder = null;
|
||||
onColumnHeaderClick(e) {
|
||||
let event = e.originalEvent;
|
||||
let column = e.column;
|
||||
|
||||
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')) {
|
||||
const targetNode = event.target;
|
||||
const columnField = this.columnProp(column, 'sortField') || this.columnProp(column, 'field');
|
||||
|
@ -786,20 +723,6 @@ export default {
|
|||
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() {
|
||||
if (this.columns) {
|
||||
for (let col of this.columns) {
|
||||
|
@ -933,6 +856,8 @@ export default {
|
|||
components: {
|
||||
'TTRow': TreeTableRow,
|
||||
'TTPaginator': Paginator,
|
||||
'TTHeaderCell': HeaderCell,
|
||||
'TTFooterCell': FooterCell
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,21 +1,10 @@
|
|||
<template>
|
||||
<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">
|
||||
<td v-if="!columnProp(col, 'hidden')" :style="[columnProp(col, 'style'),columnProp(col, 'bodyStyle')]" :class="getColumnBodyClass(col)">
|
||||
<button type="button" class="p-treetable-toggler p-link" @click="toggle" v-if="columnProp(col, '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(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>
|
||||
<TTBodyCell v-if="!columnProp(col, 'hidden')" :column="col" :node="node"
|
||||
:level="level" :leaf="leaf" :indentation="indentation" :expanded="expanded" :selectionMode="selectionMode"
|
||||
:checked="checked" :partialChecked="partialChecked"
|
||||
@node-toggle="$emit('node-toggle', $event)" @checkbox-toggle="toggleCheckbox"></TTBodyCell>
|
||||
</template>
|
||||
</tr>
|
||||
<template v-if="expanded && node.children && node.children.length">
|
||||
|
@ -26,9 +15,8 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {ObjectUtils} from 'primevue/utils';
|
||||
import {DomHandler} from 'primevue/utils';
|
||||
import Ripple from 'primevue/ripple';
|
||||
import BodyCell from './BodyCell.vue';
|
||||
|
||||
export default {
|
||||
name: 'TreeTableRow',
|
||||
|
@ -67,19 +55,11 @@ export default {
|
|||
default: 1
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
checkboxFocused: false
|
||||
}
|
||||
},
|
||||
nodeTouched: false,
|
||||
methods: {
|
||||
columnProp(col, prop) {
|
||||
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() {
|
||||
this.$emit('node-toggle', this.node);
|
||||
},
|
||||
|
@ -207,12 +187,6 @@ export default {
|
|||
selectionKeys: _selectionKeys
|
||||
});
|
||||
},
|
||||
onCheckboxFocus() {
|
||||
this.checkboxFocused = true;
|
||||
},
|
||||
onCheckboxBlur() {
|
||||
this.checkboxFocused = false;
|
||||
},
|
||||
onCheckboxChange(event) {
|
||||
let check = event.check;
|
||||
let _selectionKeys = {...event.selectionKeys};
|
||||
|
@ -245,12 +219,7 @@ export default {
|
|||
check: event.check,
|
||||
selectionKeys: _selectionKeys
|
||||
});
|
||||
},
|
||||
getColumnBodyClass(column) {
|
||||
return [this.columnProp(column, 'bodyClass'), {
|
||||
'p-frozen-column': this.columnProp(column, 'frozen')
|
||||
}];
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
containerClass() {
|
||||
|
@ -270,27 +239,9 @@ export default {
|
|||
selected() {
|
||||
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() {
|
||||
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() {
|
||||
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;
|
||||
}
|
||||
},
|
||||
directives: {
|
||||
'ripple': Ripple
|
||||
components: {
|
||||
'TTBodyCell': BodyCell
|
||||
}
|
||||
}
|
||||
</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>
|
||||
|
||||
<h5>Lazy</h5>
|
||||
|
@ -1457,6 +1535,24 @@ export default {
|
|||
<td>boolean</td>
|
||||
<td>false</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>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
{{node.children ? node.children.length : 0}}
|
||||
</template>
|
||||
</Column>
|
||||
<Column header="Options" style="width:200px" alignFrozen="right" :frozen="balanceFrozen">
|
||||
<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>
|
||||
|
@ -109,35 +109,81 @@ export default {
|
|||
<template>
|
||||
<div>
|
||||
<div class="card">
|
||||
<TreeTable :value="nodes" class="p-treetable-sm" style="margin-bottom: 2rem">
|
||||
<template #header>
|
||||
Small Table
|
||||
</template>
|
||||
<Column field="name" header="Name" :expander="true"></Column>
|
||||
<Column field="size" header="Size"></Column>
|
||||
<Column field="type" header="Type"></Column>
|
||||
<h5>Vertical</h5>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<TreeTable :value="nodes" style="margin-bottom: 2rem">
|
||||
<template #header>
|
||||
Normal Table
|
||||
</template>
|
||||
<Column field="name" header="Name" :expander="true"></Column>
|
||||
<Column field="size" header="Size"></Column>
|
||||
<Column field="type" header="Type"></Column>
|
||||
<h5>Flexible Scroll</h5>
|
||||
<p>Flex scroll feature makes the scrollable viewport section dynamic insteaf of a fixed value so that it can grow or shrink relative to the parent size of the table.
|
||||
Click the button below to display a maximizable Dialog where data viewport adjusts itself according to the size changes.</p>
|
||||
|
||||
<Button label="Show" icon="pi pi-external-link" @click="openDialog" />
|
||||
</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>
|
||||
</Dialog>
|
||||
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<TreeTable :value="nodes" class="p-treetable-lg" >
|
||||
<template #header>
|
||||
Large Table
|
||||
</template>
|
||||
<Column field="name" header="Name" :expander="true"></Column>
|
||||
<Column field="size" header="Size"></Column>
|
||||
<Column field="type" header="Type"></Column>
|
||||
<h5>Frozen Columns</h5>
|
||||
<ToggleButton v-model="optionsFrozen" onIcon="pi pi-lock" offIcon="pi pi-lock-open" onLabel="Unfreeze Options" offLabel="Freeze Options" style="width: 12rem" />
|
||||
|
||||
<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>
|
||||
</Column>
|
||||
<Column field="size" header="Size" style="width:300px"></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>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -149,7 +195,9 @@ import NodeService from './service/NodeService';
|
|||
export default {
|
||||
data() {
|
||||
return {
|
||||
nodes: null
|
||||
nodes: null,
|
||||
dialogVisible: false,
|
||||
optionsFrozen: false
|
||||
}
|
||||
},
|
||||
nodeService: null,
|
||||
|
@ -158,6 +206,14 @@ export default {
|
|||
},
|
||||
mounted() {
|
||||
this.nodeService.getTreeTableNodes().then(data => this.nodes = data);
|
||||
},
|
||||
methods: {
|
||||
openDialog() {
|
||||
this.dialogVisible = true;
|
||||
},
|
||||
closeDialog() {
|
||||
this.dialogVisible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
<\\/script>
|
||||
|
@ -169,35 +225,81 @@ export default {
|
|||
<template>
|
||||
<div>
|
||||
<div class="card">
|
||||
<TreeTable :value="nodes" class="p-treetable-sm" style="margin-bottom: 2rem">
|
||||
<template #header>
|
||||
Small Table
|
||||
</template>
|
||||
<Column field="name" header="Name" :expander="true"></Column>
|
||||
<Column field="size" header="Size"></Column>
|
||||
<Column field="type" header="Type"></Column>
|
||||
<h5>Vertical</h5>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<TreeTable :value="nodes" style="margin-bottom: 2rem">
|
||||
<template #header>
|
||||
Normal Table
|
||||
</template>
|
||||
<Column field="name" header="Name" :expander="true"></Column>
|
||||
<Column field="size" header="Size"></Column>
|
||||
<Column field="type" header="Type"></Column>
|
||||
<h5>Flexible Scroll</h5>
|
||||
<p>Flex scroll feature makes the scrollable viewport section dynamic insteaf of a fixed value so that it can grow or shrink relative to the parent size of the table.
|
||||
Click the button below to display a maximizable Dialog where data viewport adjusts itself according to the size changes.</p>
|
||||
|
||||
<Button label="Show" icon="pi pi-external-link" @click="openDialog" />
|
||||
</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>
|
||||
</Dialog>
|
||||
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<TreeTable :value="nodes" class="p-treetable-lg" >
|
||||
<template #header>
|
||||
Large Table
|
||||
</template>
|
||||
<Column field="name" header="Name" :expander="true"></Column>
|
||||
<Column field="size" header="Size"></Column>
|
||||
<Column field="type" header="Type"></Column>
|
||||
<h5>Frozen Columns</h5>
|
||||
<ToggleButton v-model="optionsFrozen" onIcon="pi pi-lock" offIcon="pi pi-lock-open" onLabel="Unfreeze Options" offLabel="Freeze Options" style="width: 12rem" />
|
||||
|
||||
<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>
|
||||
</Column>
|
||||
<Column field="size" header="Size" style="width:300px"></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>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -215,8 +317,17 @@ export default {
|
|||
|
||||
const nodes = ref();
|
||||
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>
|
||||
|
@ -242,3 +353,9 @@ export default {
|
|||
}
|
||||
}
|
||||
</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 nodeService = ref(new NodeService());
|
||||
const nodeService = new NodeService();
|
||||
|
||||
return { nodes, nodeService }
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue