Checkbox Selection for TreeTable
parent
0ef6de80a3
commit
9656540538
|
@ -36,8 +36,8 @@
|
||||||
<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" @node-click="onNodeClick"
|
:expandedKeys="d_expandedKeys" @node-toggle="onNodeToggle"
|
||||||
:selectionMode="selectionMode" :selectionKeys="selectionKeys"></TTRow>
|
:selectionMode="selectionMode" :selectionKeys="selectionKeys" @node-click="onNodeClick" @checkbox-change="onCheckboxChange"></TTRow>
|
||||||
</template>
|
</template>
|
||||||
<tr v-else class="p-treetable-emptymessage">
|
<tr v-else class="p-treetable-emptymessage">
|
||||||
<td :colspan="columns.length">
|
<td :colspan="columns.length">
|
||||||
|
@ -232,7 +232,7 @@ export default {
|
||||||
this.$emit('update:expandedKeys', this.d_expandedKeys);
|
this.$emit('update:expandedKeys', this.d_expandedKeys);
|
||||||
},
|
},
|
||||||
onNodeClick(event) {
|
onNodeClick(event) {
|
||||||
if (this.selectionMode != null && event.node.selectable !== false) {
|
if (this.rowSelectionMode && event.node.selectable !== false) {
|
||||||
const metaSelection = event.nodeTouched ? false : this.metaKeySelection;
|
const metaSelection = event.nodeTouched ? false : this.metaKeySelection;
|
||||||
const _selectionKeys = metaSelection ? this.handleSelectionWithMetaKey(event) : this.handleSelectionWithoutMetaKey(event);
|
const _selectionKeys = metaSelection ? this.handleSelectionWithMetaKey(event) : this.handleSelectionWithoutMetaKey(event);
|
||||||
|
|
||||||
|
@ -304,6 +304,14 @@ export default {
|
||||||
|
|
||||||
return _selectionKeys;
|
return _selectionKeys;
|
||||||
},
|
},
|
||||||
|
onCheckboxChange(event) {
|
||||||
|
this.$emit('update:selectionKeys', event.selectionKeys);
|
||||||
|
|
||||||
|
if (event.check)
|
||||||
|
this.$emit('node-select', event.node);
|
||||||
|
else
|
||||||
|
this.$emit('node-unselect', event.node);
|
||||||
|
},
|
||||||
isSingleSelectionMode() {
|
isSingleSelectionMode() {
|
||||||
return this.selectionMode === 'single';
|
return this.selectionMode === 'single';
|
||||||
},
|
},
|
||||||
|
@ -595,7 +603,7 @@ export default {
|
||||||
computed: {
|
computed: {
|
||||||
containerClass() {
|
containerClass() {
|
||||||
return ['p-treetable p-component', {
|
return ['p-treetable p-component', {
|
||||||
'p-treetable-hoverable-rows': (this.rowHover || this.selectionMode),
|
'p-treetable-hoverable-rows': (this.rowHover || this.rowSelectionMode),
|
||||||
'p-treetable-auto-layout': this.autoLayout
|
'p-treetable-auto-layout': this.autoLayout
|
||||||
}];
|
}];
|
||||||
},
|
},
|
||||||
|
@ -673,6 +681,15 @@ export default {
|
||||||
paginatorBottom() {
|
paginatorBottom() {
|
||||||
return this.paginator && (this.paginatorPosition !== 'top' || this.paginatorPosition === 'both');
|
return this.paginator && (this.paginatorPosition !== 'top' || this.paginatorPosition === 'both');
|
||||||
},
|
},
|
||||||
|
singleSelectionMode() {
|
||||||
|
return this.selectionMode && this.selectionMode === 'single';
|
||||||
|
},
|
||||||
|
multipleSelectionMode() {
|
||||||
|
return this.selectionMode && this.selectionMode === 'multiple';
|
||||||
|
},
|
||||||
|
rowSelectionMode() {
|
||||||
|
return this.singleSelectionMode || this.multipleSelectionMode;
|
||||||
|
},
|
||||||
totalRecordsLength() {
|
totalRecordsLength() {
|
||||||
if (this.lazy) {
|
if (this.lazy) {
|
||||||
return this.totalRecords;
|
return this.totalRecords;
|
||||||
|
|
|
@ -4,6 +4,14 @@
|
||||||
<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>
|
||||||
</span>
|
</span>
|
||||||
|
<div class="p-checkbox p-treetable-checkbox p-component" @click="toggleCheckbox" v-if="checkboxSelectionMode">
|
||||||
|
<div class="p-hidden-accessible">
|
||||||
|
<input type="checkbox" />
|
||||||
|
</div>
|
||||||
|
<div :class="checkboxClass">
|
||||||
|
<span :class="checkboxIcon"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<TTColumnSlot :data="node" :column="col" type="body" v-if="col.$scopedSlots.body" />
|
<TTColumnSlot :data="node" :column="col" type="body" v-if="col.$scopedSlots.body" />
|
||||||
<template v-else>{{resolveFieldData(node.data, col.field)}}</template>
|
<template v-else>{{resolveFieldData(node.data, col.field)}}</template>
|
||||||
</td>
|
</td>
|
||||||
|
@ -22,6 +30,10 @@ export default {
|
||||||
type: null,
|
type: null,
|
||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
|
parentNode: {
|
||||||
|
type: null,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
columns: {
|
columns: {
|
||||||
type: null,
|
type: null,
|
||||||
default: null
|
default: null
|
||||||
|
@ -52,34 +64,82 @@ export default {
|
||||||
this.$emit('node-toggle', this.node);
|
this.$emit('node-toggle', this.node);
|
||||||
},
|
},
|
||||||
onClick(event) {
|
onClick(event) {
|
||||||
if (DomHandler.hasClass(event.target, 'p-treetable-toggler') || DomHandler.hasClass(event.target, 'p-treetable-toggler-icon')) {
|
let targetNode = event.target.nodeName;
|
||||||
|
if (targetNode === 'INPUT' || targetNode === 'BUTTON' || targetNode === 'A' || DomHandler.hasClass(event.target, 'p-clickable')
|
||||||
|
|| DomHandler.hasClass(event.target, 'p-treetable-toggler') || DomHandler.hasClass(event.target.parentElement, 'p-treetable-toggler')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isCheckboxSelectionMode()) {
|
|
||||||
this.toggleCheckbox();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.$emit('node-click', {
|
this.$emit('node-click', {
|
||||||
originalEvent: event,
|
originalEvent: event,
|
||||||
nodeTouched: this.nodeTouched,
|
nodeTouched: this.nodeTouched,
|
||||||
node: this.node
|
node: this.node
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
this.nodeTouched = false;
|
this.nodeTouched = false;
|
||||||
},
|
|
||||||
isCheckboxSelectionMode() {
|
|
||||||
return this.selectionMode === 'checkbox';
|
|
||||||
},
|
|
||||||
toggleCheckbox() {
|
|
||||||
|
|
||||||
},
|
},
|
||||||
onTouchEnd() {
|
onTouchEnd() {
|
||||||
this.nodeTouched = true;
|
this.nodeTouched = true;
|
||||||
},
|
},
|
||||||
onKeyDown(event) {
|
onKeyDown(event) {
|
||||||
//todo
|
//todo
|
||||||
|
},
|
||||||
|
toggleCheckbox() {
|
||||||
|
let _selectionKeys = this.selectionKeys ? {...this.selectionKeys} : {};
|
||||||
|
const _check = !this.checked;
|
||||||
|
|
||||||
|
this.propagateDown(this.node, _check, _selectionKeys);
|
||||||
|
|
||||||
|
this.$emit('checkbox-change', {
|
||||||
|
node: this.node,
|
||||||
|
check: _check,
|
||||||
|
selectionKeys: _selectionKeys
|
||||||
|
});
|
||||||
|
},
|
||||||
|
propagateDown(node, check, selectionKeys) {
|
||||||
|
if (check)
|
||||||
|
selectionKeys[node.key] = {checked: true, partialChecked: false};
|
||||||
|
else
|
||||||
|
delete selectionKeys[node.key];
|
||||||
|
|
||||||
|
if (node.children && node.children.length) {
|
||||||
|
for (let child of node.children) {
|
||||||
|
this.propagateDown(child, check, selectionKeys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
propagateUp(event) {
|
||||||
|
let check = event.check;
|
||||||
|
let _selectionKeys = {...event.selectionKeys};
|
||||||
|
let checkedChildCount = 0;
|
||||||
|
let childPartialSelected = false;
|
||||||
|
|
||||||
|
for(let child of this.node.children) {
|
||||||
|
if(_selectionKeys[child.key] && _selectionKeys[child.key].checked)
|
||||||
|
checkedChildCount++;
|
||||||
|
else if(_selectionKeys[child.key] && _selectionKeys[child.key].partialChecked)
|
||||||
|
childPartialSelected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(check && checkedChildCount === this.node.children.length) {
|
||||||
|
_selectionKeys[this.node.key] = {checked: true, partialChecked: false};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!check) {
|
||||||
|
delete _selectionKeys[this.node.key];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(childPartialSelected || (checkedChildCount > 0 && checkedChildCount !== this.node.children.length))
|
||||||
|
_selectionKeys[this.node.key] = {checked: false, partialChecked: true};
|
||||||
|
else
|
||||||
|
_selectionKeys[this.node.key] = {checked: false, partialChecked: false};
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$emit('checkbox-change', {
|
||||||
|
node: event.node,
|
||||||
|
check: event.check,
|
||||||
|
selectionKeys: _selectionKeys
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -111,6 +171,21 @@ export default {
|
||||||
},
|
},
|
||||||
childLevel() {
|
childLevel() {
|
||||||
return this.level + 1;
|
return this.level + 1;
|
||||||
|
},
|
||||||
|
checkboxSelectionMode() {
|
||||||
|
return this.selectionMode === 'checkbox';
|
||||||
|
},
|
||||||
|
checkboxClass() {
|
||||||
|
return ['p-checkbox-box', {'p-highlight': this.checked}];
|
||||||
|
},
|
||||||
|
checkboxIcon() {
|
||||||
|
return ['p-checkbox-icon p-c', {'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;
|
||||||
|
},
|
||||||
|
partialChecked() {
|
||||||
|
return this.selectionKeys ? this.selectionKeys[this.node.key] && this.selectionKeys[this.node.key].partialChecked: false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -34,7 +34,8 @@ const TreeTableRowLoader = {
|
||||||
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']
|
'node-click': context.listeners['node-click'],
|
||||||
|
'checkbox-change': context.listeners['checkbox-change']
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -46,13 +47,47 @@ const TreeTableRowLoader = {
|
||||||
for (let childNode of node.children) {
|
for (let childNode of node.children) {
|
||||||
let childNodeProps = {...context.props};
|
let childNodeProps = {...context.props};
|
||||||
childNodeProps.node = childNode;
|
childNodeProps.node = childNode;
|
||||||
|
childNodeProps.parentNode = node;
|
||||||
childNodeProps.level = context.props.level + 1;
|
childNodeProps.level = context.props.level + 1;
|
||||||
|
|
||||||
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']
|
'node-click': context.listeners['node-click'],
|
||||||
|
'checkbox-change': (event) => {
|
||||||
|
let check = event.check;
|
||||||
|
let _selectionKeys = {...event.selectionKeys};
|
||||||
|
let checkedChildCount = 0;
|
||||||
|
let childPartialSelected = false;
|
||||||
|
|
||||||
|
for(let child of node.children) {
|
||||||
|
if(_selectionKeys[child.key] && _selectionKeys[child.key].checked)
|
||||||
|
checkedChildCount++;
|
||||||
|
else if(_selectionKeys[child.key] && _selectionKeys[child.key].partialChecked)
|
||||||
|
childPartialSelected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(check && checkedChildCount === node.children.length) {
|
||||||
|
_selectionKeys[node.key] = {checked: true, partialChecked: false};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!check) {
|
||||||
|
delete _selectionKeys[node.key];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(childPartialSelected || (checkedChildCount > 0 && checkedChildCount !== node.children.length))
|
||||||
|
_selectionKeys[node.key] = {checked: false, partialChecked: true};
|
||||||
|
else
|
||||||
|
_selectionKeys[node.key] = {checked: false, partialChecked: false};
|
||||||
|
}
|
||||||
|
|
||||||
|
context.listeners['checkbox-change']({
|
||||||
|
node: event.node,
|
||||||
|
check: event.check,
|
||||||
|
selectionKeys: _selectionKeys
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue