From f645b96ee83195c07ab23209e7d77473fbf1ef3d Mon Sep 17 00:00:00 2001 From: cagataycivici Date: Thu, 1 Aug 2019 23:56:05 +0300 Subject: [PATCH] Checkbox selection for Tree --- src/components/tree/Tree.vue | 74 ++++++++++++++----- src/components/tree/TreeNode.vue | 104 +++++++++++++++++++++++++-- src/views/tree/TreeSelectionDemo.vue | 6 +- 3 files changed, 155 insertions(+), 29 deletions(-) diff --git a/src/components/tree/Tree.vue b/src/components/tree/Tree.vue index c9cd119b8..f5e34f8da 100644 --- a/src/components/tree/Tree.vue +++ b/src/components/tree/Tree.vue @@ -3,7 +3,7 @@ @@ -33,14 +33,6 @@ export default { type: Boolean, default: true }, - propagateSelectionDown: { - type: Boolean, - default: true - }, - propagateSelectionUp: { - type: Boolean, - default: true - }, loading: { type: Boolean, default: false @@ -78,19 +70,20 @@ export default { }, onNodeClick(event) { if (this.selectionMode != null && event.node.selectable !== false) { - let _selectionKeys; - - if (this.isCheckboxSelectionMode()) { - - } - else { - const metaSelection = event.nodeTouched ? false : this.metaKeySelection; - _selectionKeys = metaSelection ? this.handleSelectionWithMetaKey(event) : this.handleSelectionWithoutMetaKey(event); - } + const metaSelection = event.nodeTouched ? false : this.metaKeySelection; + const _selectionKeys = metaSelection ? this.handleSelectionWithMetaKey(event) : this.handleSelectionWithoutMetaKey(event); this.$emit('update:selectionKeys', _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); + }, handleSelectionWithMetaKey(event) { const originalEvent = event.originalEvent; const node = event.node; @@ -156,6 +149,46 @@ export default { return _selectionKeys; }, + /*handleCheckboxSelection(event) { + const node = event.node; + const checked = this.isChecked(node); + let _selectionKeys = this.selectionKeys ? {...this.selectionKeys} : {}; + + if (checked) { + if (this.propagateSelectionDown) + this.propagateDown(node, false, _selectionKeys); + else + delete _selectionKeys[node.key]; + + if (this.propagateSelectionUp && this.props.onPropagateUp) { + this.props.onPropagateUp({ + originalEvent: event, + check: false, + selectionKeys: selectionKeys + }); + } + + this.$emit('node-unselect', node); + } + else { + if (this.props.propagateSelectionDown) + this.propagateDown(this.props.node, true, selectionKeys); + else + selectionKeys[this.props.node.key] = {checked: true}; + + if (this.props.propagateSelectionUp && this.props.onPropagateUp) { + this.props.onPropagateUp({ + originalEvent: event, + check: true, + selectionKeys: selectionKeys + }); + } + + this.$emit('node-select', node); + } + + return _selectionKeys; + },*/ isCheckboxSelectionMode() { return this.selectionMode === 'checkbox'; }, @@ -167,7 +200,10 @@ export default { }, isSelected(node) { return (this.selectionMode && this.selectionKeys) ? this.selectionKeys[node.key] === true : false; - } + }, + isChecked(node) { + return this.selectionKeys ? this.selectionKeys[node.key] && this.selectionKeys[node.key].checked: false; + }, }, computed: { containerClass() { diff --git a/src/components/tree/TreeNode.vue b/src/components/tree/TreeNode.vue index e54369ba7..cf19d7f1c 100644 --- a/src/components/tree/TreeNode.vue +++ b/src/components/tree/TreeNode.vue @@ -5,13 +5,19 @@ +
+
+ +
+
{{node.label}} @@ -52,11 +58,17 @@ export default { return; } - this.$emit('node-click', { - originalEvent: event, - nodeTouched: this.nodeTouched, - node: this.node - }); + if (this.isCheckboxSelectionMode()) { + this.toggleCheckbox(); + } + else { + this.$emit('node-click', { + originalEvent: event, + nodeTouched: this.nodeTouched, + node: this.node + }); + } + this.nodeTouched = false; }, onChildNodeClick(event) { @@ -125,6 +137,66 @@ export default { break; } }, + 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 + }); + }, + onChildCheckboxChange(event) { + this.$emit('checkbox-change', event); + }, findNextSiblingOfAncestor(nodeElement) { let parentNodeElement = this.getParentNodeElement(nodeElement); if (parentNodeElement) { @@ -155,6 +227,9 @@ export default { }, focusNode(element) { element.children[0].focus(); + }, + isCheckboxSelectionMode() { + return this.selectionMode === 'checkbox'; } }, computed: { @@ -179,7 +254,7 @@ export default { contentClass() { return ['p-treenode-content', { 'p-treenode-selectable': this.selectable, - 'p-highlight': this.selected + 'p-highlight': this.checkboxMode ? this.checked : this.selected }]; }, icon() { @@ -190,6 +265,21 @@ export default { 'pi-caret-down': this.expanded, 'pi-caret-right': !this.expanded }]; + }, + 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}]; + }, + checkboxMode() { + return this.selectionMode === 'checkbox' && this.node.selectable !== false; + }, + 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; } } } diff --git a/src/views/tree/TreeSelectionDemo.vue b/src/views/tree/TreeSelectionDemo.vue index 65926ffae..5094104b7 100644 --- a/src/views/tree/TreeSelectionDemo.vue +++ b/src/views/tree/TreeSelectionDemo.vue @@ -12,15 +12,15 @@

Single Selection

- {{selectedKey}}

Multiple Selection with MetaKey

- {{selectedKeys1}}

Multiple Selection without MetaKey

- {{selectedKeys2}} + +

Checkbox Selection

+