Single and Multiple Selection for TreeTable
parent
b6e91552bb
commit
0ef6de80a3
|
@ -983,6 +983,10 @@ export default {
|
||||||
table-layout: auto;
|
table-layout: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.p-datatable-hoverable-rows .p-datatable-tbody > tr.p-highlight {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
/* Sections */
|
/* Sections */
|
||||||
.p-datatable-header,
|
.p-datatable-header,
|
||||||
.p-datatable-footer {
|
.p-datatable-footer {
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
<tbody class="p-treetable-tbody">
|
<tbody class="p-treetable-tbody">
|
||||||
<template v-if="!empty">
|
<template v-if="!empty">
|
||||||
<TTRow v-for="node of dataToRender" :key="node.key" :columns="columns" :node="node" :level="0"
|
<TTRow v-for="node of dataToRender" :key="node.key" :columns="columns" :node="node" :level="0"
|
||||||
:expandedKeys="d_expandedKeys" @node-toggle="onNodeToggle"
|
:expandedKeys="d_expandedKeys" @node-toggle="onNodeToggle" @node-click="onNodeClick"
|
||||||
:selectionMode="selectionMode" :selectionKeys="selectionKeys"></TTRow>
|
:selectionMode="selectionMode" :selectionKeys="selectionKeys"></TTRow>
|
||||||
</template>
|
</template>
|
||||||
<tr v-else class="p-treetable-emptymessage">
|
<tr v-else class="p-treetable-emptymessage">
|
||||||
|
@ -231,6 +231,85 @@ export default {
|
||||||
this.d_expandedKeys = {...this.d_expandedKeys};
|
this.d_expandedKeys = {...this.d_expandedKeys};
|
||||||
this.$emit('update:expandedKeys', this.d_expandedKeys);
|
this.$emit('update:expandedKeys', this.d_expandedKeys);
|
||||||
},
|
},
|
||||||
|
onNodeClick(event) {
|
||||||
|
if (this.selectionMode != null && event.node.selectable !== false) {
|
||||||
|
const metaSelection = event.nodeTouched ? false : this.metaKeySelection;
|
||||||
|
const _selectionKeys = metaSelection ? this.handleSelectionWithMetaKey(event) : this.handleSelectionWithoutMetaKey(event);
|
||||||
|
|
||||||
|
this.$emit('update:selectionKeys', _selectionKeys);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleSelectionWithMetaKey(event) {
|
||||||
|
const originalEvent = event.originalEvent;
|
||||||
|
const node = event.node;
|
||||||
|
const metaKey = (originalEvent.metaKey||originalEvent.ctrlKey);
|
||||||
|
const selected = this.isNodeSelected(node);
|
||||||
|
let _selectionKeys;
|
||||||
|
|
||||||
|
if (selected && metaKey) {
|
||||||
|
if (this.isSingleSelectionMode()) {
|
||||||
|
_selectionKeys = {};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_selectionKeys = {...this.selectionKeys};
|
||||||
|
delete _selectionKeys[node.key];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$emit('node-unselect', node);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (this.isSingleSelectionMode()) {
|
||||||
|
_selectionKeys = {};
|
||||||
|
}
|
||||||
|
else if (this.isMultipleSelectionMode()) {
|
||||||
|
_selectionKeys = !metaKey ? {} : (this.selectionKeys ? {...this.selectionKeys} : {});
|
||||||
|
}
|
||||||
|
|
||||||
|
_selectionKeys[node.key] = true;
|
||||||
|
this.$emit('node-select', node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _selectionKeys;
|
||||||
|
},
|
||||||
|
handleSelectionWithoutMetaKey(event) {
|
||||||
|
const node = event.node;
|
||||||
|
const selected = this.isNodeSelected(node);
|
||||||
|
let _selectionKeys;
|
||||||
|
|
||||||
|
if (this.isSingleSelectionMode()) {
|
||||||
|
if (selected) {
|
||||||
|
_selectionKeys = {};
|
||||||
|
this.$emit('node-unselect', node);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_selectionKeys = {};
|
||||||
|
_selectionKeys[node.key] = true;
|
||||||
|
this.$emit('node-select', node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (selected) {
|
||||||
|
_selectionKeys = {...this.selectionKeys};
|
||||||
|
delete _selectionKeys[node.key];
|
||||||
|
|
||||||
|
this.$emit('node-unselect', node);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_selectionKeys = this.selectionKeys ? {...this.selectionKeys} : {};
|
||||||
|
_selectionKeys[node.key] = true;
|
||||||
|
|
||||||
|
this.$emit('node-select', node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _selectionKeys;
|
||||||
|
},
|
||||||
|
isSingleSelectionMode() {
|
||||||
|
return this.selectionMode === 'single';
|
||||||
|
},
|
||||||
|
isMultipleSelectionMode() {
|
||||||
|
return this.selectionMode === 'multiple';
|
||||||
|
},
|
||||||
onPage(event) {
|
onPage(event) {
|
||||||
this.d_first = event.first;
|
this.d_first = event.first;
|
||||||
this.d_rows = event.rows;
|
this.d_rows = event.rows;
|
||||||
|
@ -655,6 +734,10 @@ export default {
|
||||||
table-layout: auto;
|
table-layout: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.p-treetable-hoverable-rows .p-treetable-tbody > tr.p-highlight {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
/* Sections */
|
/* Sections */
|
||||||
.p-treetable-header,
|
.p-treetable-header,
|
||||||
.p-treetable-footer {
|
.p-treetable-footer {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<tr :class="containerClass">
|
<tr :class="containerClass" @click="onClick" @keydown="onKeyDown" @touchend="onTouchEnd" :style="node.style">
|
||||||
<td v-for="(col,i) of columns" :key="col.columnKey||col.field||i" :style="col.bodyStyle" :class="col.bodyClass">
|
<td v-for="(col,i) of columns" :key="col.columnKey||col.field||i" :style="col.bodyStyle" :class="col.bodyClass">
|
||||||
<span class="p-treetable-toggler p-unselectable-text" @click="toggle" v-if="col.expander" :style="togglerStyle">
|
<span class="p-treetable-toggler p-unselectable-text" @click="toggle" v-if="col.expander" :style="togglerStyle">
|
||||||
<i :class="togglerIcon"></i>
|
<i :class="togglerIcon"></i>
|
||||||
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ObjectUtils from '../utils/ObjectUtils';
|
import ObjectUtils from '../utils/ObjectUtils';
|
||||||
|
import DomHandler from '../utils/DomHandler';
|
||||||
import TreeTableColumnSlot from './TreeTableColumnSlot';
|
import TreeTableColumnSlot from './TreeTableColumnSlot';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -42,6 +43,7 @@ export default {
|
||||||
default: 0
|
default: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
nodeTouched: false,
|
||||||
methods: {
|
methods: {
|
||||||
resolveFieldData(rowData, field) {
|
resolveFieldData(rowData, field) {
|
||||||
return ObjectUtils.resolveFieldData(rowData, field);
|
return ObjectUtils.resolveFieldData(rowData, field);
|
||||||
|
@ -49,8 +51,35 @@ export default {
|
||||||
toggle() {
|
toggle() {
|
||||||
this.$emit('node-toggle', this.node);
|
this.$emit('node-toggle', this.node);
|
||||||
},
|
},
|
||||||
onChildNodeToggle(node) {
|
onClick(event) {
|
||||||
this.$emit('node-toggle', node);
|
if (DomHandler.hasClass(event.target, 'p-treetable-toggler') || DomHandler.hasClass(event.target, 'p-treetable-toggler-icon')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isCheckboxSelectionMode()) {
|
||||||
|
this.toggleCheckbox();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.$emit('node-click', {
|
||||||
|
originalEvent: event,
|
||||||
|
nodeTouched: this.nodeTouched,
|
||||||
|
node: this.node
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.nodeTouched = false;
|
||||||
|
},
|
||||||
|
isCheckboxSelectionMode() {
|
||||||
|
return this.selectionMode === 'checkbox';
|
||||||
|
},
|
||||||
|
toggleCheckbox() {
|
||||||
|
|
||||||
|
},
|
||||||
|
onTouchEnd() {
|
||||||
|
this.nodeTouched = true;
|
||||||
|
},
|
||||||
|
onKeyDown(event) {
|
||||||
|
//todo
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
|
@ -33,7 +33,8 @@ const TreeTableRowLoader = {
|
||||||
const root = createElement(TreeTableRow, {
|
const root = createElement(TreeTableRow, {
|
||||||
props: context.props,
|
props: context.props,
|
||||||
on: {
|
on: {
|
||||||
'node-toggle': context.listeners['node-toggle']
|
'node-toggle': context.listeners['node-toggle'],
|
||||||
|
'node-click': context.listeners['node-click']
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -50,7 +51,8 @@ const TreeTableRowLoader = {
|
||||||
let childNodeElement = createElement(TreeTableRowLoader, {
|
let childNodeElement = createElement(TreeTableRowLoader, {
|
||||||
props: childNodeProps,
|
props: childNodeProps,
|
||||||
on: {
|
on: {
|
||||||
'node-toggle': context.listeners['node-toggle']
|
'node-toggle': context.listeners['node-toggle'],
|
||||||
|
'node-click': context.listeners['node-click']
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -405,6 +405,11 @@ export default new Router({
|
||||||
path: '/treetable/filter',
|
path: '/treetable/filter',
|
||||||
name: 'treetablefilter',
|
name: 'treetablefilter',
|
||||||
component: () => import('./views/treetable/TreeTableFilterDemo.vue')
|
component: () => import('./views/treetable/TreeTableFilterDemo.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/treetable/selection',
|
||||||
|
name: 'treetableselection',
|
||||||
|
component: () => import('./views/treetable/TreeTableSelectionDemo.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/tristatecheckbox',
|
path: '/tristatecheckbox',
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<TreeTableSubMenu />
|
||||||
|
|
||||||
|
<div class="content-section introduction">
|
||||||
|
<div class="feature-intro">
|
||||||
|
<h1>TreeTable - Selection</h1>
|
||||||
|
<p>TreeTable supports <b>single</b>, <b>multiple</b> and <b>checkbox</b> as selection modes.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content-section implementation">
|
||||||
|
<h3>Single Selection</h3>
|
||||||
|
<TreeTable :value="nodes" selectionMode="single" :selectionKeys.sync="selectedKey1">
|
||||||
|
<Column field="name" header="Name" :expander="true"></Column>
|
||||||
|
<Column field="size" header="Size"></Column>
|
||||||
|
<Column field="type" header="Type"></Column>
|
||||||
|
</TreeTable>
|
||||||
|
|
||||||
|
<h3>Multiple Selection with MetaKey</h3>
|
||||||
|
<TreeTable :value="nodes" selectionMode="multiple" :selectionKeys.sync="selectedKeys1">
|
||||||
|
<Column field="name" header="Name" :expander="true"></Column>
|
||||||
|
<Column field="size" header="Size"></Column>
|
||||||
|
<Column field="type" header="Type"></Column>
|
||||||
|
</TreeTable>
|
||||||
|
|
||||||
|
<h3>Multiple Selection without MetaKey</h3>
|
||||||
|
<TreeTable :value="nodes" selectionMode="multiple" :selectionKeys.sync="selectedKeys2" :metaKeySelection="false">
|
||||||
|
<Column field="name" header="Name" :expander="true"></Column>
|
||||||
|
<Column field="size" header="Size"></Column>
|
||||||
|
<Column field="type" header="Type"></Column>
|
||||||
|
</TreeTable>
|
||||||
|
|
||||||
|
<h3>Checkbox Selection</h3>
|
||||||
|
<TreeTable :value="nodes" selectionMode="checkbox" :selectionKeys.sync="selectedKeys3">
|
||||||
|
<Column field="name" header="Name" :expander="true"></Column>
|
||||||
|
<Column field="size" header="Size"></Column>
|
||||||
|
<Column field="type" header="Type"></Column>
|
||||||
|
</TreeTable>
|
||||||
|
|
||||||
|
<h3>Events</h3>
|
||||||
|
<TreeTable :value="nodes" selectionMode="single" :selectionKeys.sync="selectedKey2"
|
||||||
|
@node-select="onNodeSelect" @node-unselect="onNodeUnselect">
|
||||||
|
<Column field="name" header="Name" :expander="true"></Column>
|
||||||
|
<Column field="size" header="Size"></Column>
|
||||||
|
<Column field="type" header="Type"></Column>
|
||||||
|
</TreeTable>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<TreeTableDoc />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import NodeService from '../../service/NodeService';
|
||||||
|
import TreeTableDoc from './TreeTableDoc';
|
||||||
|
import TreeTableSubMenu from './TreeTableSubMenu';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
selectedKey1: null,
|
||||||
|
selectedKey2: null,
|
||||||
|
selectedKeys1: null,
|
||||||
|
selectedKeys2: null,
|
||||||
|
selectedKeys3: null,
|
||||||
|
nodes: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
nodeService: null,
|
||||||
|
created() {
|
||||||
|
this.nodeService = new NodeService();
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.nodeService.getTreeTableNodes().then(data => this.nodes = data);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onNodeSelect(node) {
|
||||||
|
this.$toast.add({severity:'success', summary: 'Node Selected', detail: node.data.name, life: 3000});
|
||||||
|
},
|
||||||
|
onNodeUnselect(node) {
|
||||||
|
this.$toast.add({severity:'success', summary: 'Node Unselected', detail: node.data.name, life: 3000});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
'TreeTableDoc': TreeTableDoc,
|
||||||
|
'TreeTableSubMenu': TreeTableSubMenu
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
button {
|
||||||
|
margin-right: .5em;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue