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"> <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;

View File

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

View File

@ -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
});
}
} }
}); });