Checkbox Selection for TreeTable

pull/41/head
cagataycivici 2019-08-07 14:17:03 +03:00
parent 0ef6de80a3
commit 9656540538
3 changed files with 146 additions and 19 deletions

View File

@ -36,8 +36,8 @@
<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" @node-click="onNodeClick"
:selectionMode="selectionMode" :selectionKeys="selectionKeys"></TTRow>
:expandedKeys="d_expandedKeys" @node-toggle="onNodeToggle"
:selectionMode="selectionMode" :selectionKeys="selectionKeys" @node-click="onNodeClick" @checkbox-change="onCheckboxChange"></TTRow>
</template>
<tr v-else class="p-treetable-emptymessage">
<td :colspan="columns.length">
@ -232,7 +232,7 @@ export default {
this.$emit('update:expandedKeys', this.d_expandedKeys);
},
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 _selectionKeys = metaSelection ? this.handleSelectionWithMetaKey(event) : this.handleSelectionWithoutMetaKey(event);
@ -304,6 +304,14 @@ export default {
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() {
return this.selectionMode === 'single';
},
@ -595,7 +603,7 @@ export default {
computed: {
containerClass() {
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
}];
},
@ -673,6 +681,15 @@ export default {
paginatorBottom() {
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() {
if (this.lazy) {
return this.totalRecords;

View File

@ -4,6 +4,14 @@
<span class="p-treetable-toggler p-unselectable-text" @click="toggle" v-if="col.expander" :style="togglerStyle">
<i :class="togglerIcon"></i>
</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" />
<template v-else>{{resolveFieldData(node.data, col.field)}}</template>
</td>
@ -22,6 +30,10 @@ export default {
type: null,
default: null
},
parentNode: {
type: null,
default: null
},
columns: {
type: null,
default: null
@ -52,34 +64,82 @@ export default {
this.$emit('node-toggle', this.node);
},
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;
}
if (this.isCheckboxSelectionMode()) {
this.toggleCheckbox();
}
else {
this.$emit('node-click', {
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
},
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: {
@ -111,6 +171,21 @@ export default {
},
childLevel() {
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: {

View File

@ -34,7 +34,8 @@ const TreeTableRowLoader = {
props: context.props,
on: {
'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) {
let childNodeProps = {...context.props};
childNodeProps.node = childNode;
childNodeProps.parentNode = node;
childNodeProps.level = context.props.level + 1;
let childNodeElement = createElement(TreeTableRowLoader, {
props: childNodeProps,
on: {
'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
});
}
}
});