Single and Multiple Selection for TreeTable

pull/41/head
cagataycivici 2019-08-07 12:40:29 +03:00
parent b6e91552bb
commit 0ef6de80a3
6 changed files with 225 additions and 6 deletions

View File

@ -983,6 +983,10 @@ export default {
table-layout: auto;
}
.p-datatable-hoverable-rows .p-datatable-tbody > tr.p-highlight {
cursor: pointer;
}
/* Sections */
.p-datatable-header,
.p-datatable-footer {

View File

@ -36,7 +36,7 @@
<tbody class="p-treetable-tbody">
<template v-if="!empty">
<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>
</template>
<tr v-else class="p-treetable-emptymessage">
@ -231,6 +231,85 @@ export default {
this.d_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) {
this.d_first = event.first;
this.d_rows = event.rows;
@ -655,6 +734,10 @@ export default {
table-layout: auto;
}
.p-treetable-hoverable-rows .p-treetable-tbody > tr.p-highlight {
cursor: pointer;
}
/* Sections */
.p-treetable-header,
.p-treetable-footer {

View File

@ -1,5 +1,5 @@
<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">
<span class="p-treetable-toggler p-unselectable-text" @click="toggle" v-if="col.expander" :style="togglerStyle">
<i :class="togglerIcon"></i>
@ -12,6 +12,7 @@
<script>
import ObjectUtils from '../utils/ObjectUtils';
import DomHandler from '../utils/DomHandler';
import TreeTableColumnSlot from './TreeTableColumnSlot';
export default {
@ -42,6 +43,7 @@ export default {
default: 0
}
},
nodeTouched: false,
methods: {
resolveFieldData(rowData, field) {
return ObjectUtils.resolveFieldData(rowData, field);
@ -49,8 +51,35 @@ export default {
toggle() {
this.$emit('node-toggle', this.node);
},
onChildNodeToggle(node) {
this.$emit('node-toggle', node);
onClick(event) {
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: {

View File

@ -33,7 +33,8 @@ const TreeTableRowLoader = {
const root = createElement(TreeTableRow, {
props: context.props,
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, {
props: childNodeProps,
on: {
'node-toggle': context.listeners['node-toggle']
'node-toggle': context.listeners['node-toggle'],
'node-click': context.listeners['node-click']
}
});

View File

@ -405,6 +405,11 @@ export default new Router({
path: '/treetable/filter',
name: 'treetablefilter',
component: () => import('./views/treetable/TreeTableFilterDemo.vue')
},
{
path: '/treetable/selection',
name: 'treetableselection',
component: () => import('./views/treetable/TreeTableSelectionDemo.vue')
},
{
path: '/tristatecheckbox',

View File

@ -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>