Checkbox selection for Tree
parent
56839ca196
commit
f645b96ee8
|
@ -3,7 +3,7 @@
|
||||||
<ul class="p-tree-container" role="tree">
|
<ul class="p-tree-container" role="tree">
|
||||||
<TreeNode v-for="node of value" :key="node.key" :node="node"
|
<TreeNode v-for="node of value" :key="node.key" :node="node"
|
||||||
:expandedKeys="d_expandedKeys" @node-toggle="onNodeToggle" @node-click="onNodeClick"
|
:expandedKeys="d_expandedKeys" @node-toggle="onNodeToggle" @node-click="onNodeClick"
|
||||||
:selectionMode="selectionMode" :selectionKeys="selectionKeys"></TreeNode>
|
:selectionMode="selectionMode" :selectionKeys="selectionKeys" @checkbox-change="onCheckboxChange"></TreeNode>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -33,14 +33,6 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
propagateSelectionDown: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
propagateSelectionUp: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
loading: {
|
loading: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
@ -78,19 +70,20 @@ export default {
|
||||||
},
|
},
|
||||||
onNodeClick(event) {
|
onNodeClick(event) {
|
||||||
if (this.selectionMode != null && event.node.selectable !== false) {
|
if (this.selectionMode != null && event.node.selectable !== false) {
|
||||||
let _selectionKeys;
|
const metaSelection = event.nodeTouched ? false : this.metaKeySelection;
|
||||||
|
const _selectionKeys = metaSelection ? this.handleSelectionWithMetaKey(event) : this.handleSelectionWithoutMetaKey(event);
|
||||||
if (this.isCheckboxSelectionMode()) {
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const metaSelection = event.nodeTouched ? false : this.metaKeySelection;
|
|
||||||
_selectionKeys = metaSelection ? this.handleSelectionWithMetaKey(event) : this.handleSelectionWithoutMetaKey(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$emit('update:selectionKeys', _selectionKeys);
|
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) {
|
handleSelectionWithMetaKey(event) {
|
||||||
const originalEvent = event.originalEvent;
|
const originalEvent = event.originalEvent;
|
||||||
const node = event.node;
|
const node = event.node;
|
||||||
|
@ -156,6 +149,46 @@ export default {
|
||||||
|
|
||||||
return _selectionKeys;
|
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() {
|
isCheckboxSelectionMode() {
|
||||||
return this.selectionMode === 'checkbox';
|
return this.selectionMode === 'checkbox';
|
||||||
},
|
},
|
||||||
|
@ -167,7 +200,10 @@ export default {
|
||||||
},
|
},
|
||||||
isSelected(node) {
|
isSelected(node) {
|
||||||
return (this.selectionMode && this.selectionKeys) ? this.selectionKeys[node.key] === true : false;
|
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: {
|
computed: {
|
||||||
containerClass() {
|
containerClass() {
|
||||||
|
|
|
@ -5,13 +5,19 @@
|
||||||
<span class="p-tree-toggler p-unselectable-text p-link" @click="toggle">
|
<span class="p-tree-toggler p-unselectable-text p-link" @click="toggle">
|
||||||
<span :class="toggleIcon"></span>
|
<span :class="toggleIcon"></span>
|
||||||
</span>
|
</span>
|
||||||
|
<div class="p-checkbox p-component" v-if="checkboxMode">
|
||||||
|
<div :class="checkboxClass">
|
||||||
|
<span :class="checkboxIcon"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<span :class="icon"></span>
|
<span :class="icon"></span>
|
||||||
<span class="p-treenode-label">{{node.label}}</span>
|
<span class="p-treenode-label">{{node.label}}</span>
|
||||||
</div>
|
</div>
|
||||||
<ul class="p-treenode-children" role="group" v-if="hasChildren && expanded">
|
<ul class="p-treenode-children" role="group" v-if="hasChildren && expanded">
|
||||||
<sub-treenode v-for="childNode of node.children" :key="childNode.key" :node="childNode"
|
<sub-treenode v-for="childNode of node.children" :key="childNode.key" :node="childNode"
|
||||||
:expandedKeys="expandedKeys" @node-toggle="onChildNodeToggle" @node-click="onChildNodeClick"
|
:expandedKeys="expandedKeys" @node-toggle="onChildNodeToggle" @node-click="onChildNodeClick"
|
||||||
:selectionMode="selectionMode" :selectionKeys="selectionKeys"></sub-treenode>
|
:selectionMode="selectionMode" :selectionKeys="selectionKeys"
|
||||||
|
@checkbox-change="propagateUp"></sub-treenode>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
@ -52,11 +58,17 @@ export default {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$emit('node-click', {
|
if (this.isCheckboxSelectionMode()) {
|
||||||
originalEvent: event,
|
this.toggleCheckbox();
|
||||||
nodeTouched: this.nodeTouched,
|
}
|
||||||
node: this.node
|
else {
|
||||||
});
|
this.$emit('node-click', {
|
||||||
|
originalEvent: event,
|
||||||
|
nodeTouched: this.nodeTouched,
|
||||||
|
node: this.node
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.nodeTouched = false;
|
this.nodeTouched = false;
|
||||||
},
|
},
|
||||||
onChildNodeClick(event) {
|
onChildNodeClick(event) {
|
||||||
|
@ -125,6 +137,66 @@ export default {
|
||||||
break;
|
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) {
|
findNextSiblingOfAncestor(nodeElement) {
|
||||||
let parentNodeElement = this.getParentNodeElement(nodeElement);
|
let parentNodeElement = this.getParentNodeElement(nodeElement);
|
||||||
if (parentNodeElement) {
|
if (parentNodeElement) {
|
||||||
|
@ -155,6 +227,9 @@ export default {
|
||||||
},
|
},
|
||||||
focusNode(element) {
|
focusNode(element) {
|
||||||
element.children[0].focus();
|
element.children[0].focus();
|
||||||
|
},
|
||||||
|
isCheckboxSelectionMode() {
|
||||||
|
return this.selectionMode === 'checkbox';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -179,7 +254,7 @@ export default {
|
||||||
contentClass() {
|
contentClass() {
|
||||||
return ['p-treenode-content', {
|
return ['p-treenode-content', {
|
||||||
'p-treenode-selectable': this.selectable,
|
'p-treenode-selectable': this.selectable,
|
||||||
'p-highlight': this.selected
|
'p-highlight': this.checkboxMode ? this.checked : this.selected
|
||||||
}];
|
}];
|
||||||
},
|
},
|
||||||
icon() {
|
icon() {
|
||||||
|
@ -190,6 +265,21 @@ export default {
|
||||||
'pi-caret-down': this.expanded,
|
'pi-caret-down': this.expanded,
|
||||||
'pi-caret-right': !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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,15 +12,15 @@
|
||||||
<div class="content-section implementation">
|
<div class="content-section implementation">
|
||||||
<h3>Single Selection</h3>
|
<h3>Single Selection</h3>
|
||||||
<Tree :value="nodes" selectionMode="single" :selectionKeys.sync="selectedKey"></Tree>
|
<Tree :value="nodes" selectionMode="single" :selectionKeys.sync="selectedKey"></Tree>
|
||||||
{{selectedKey}}
|
|
||||||
|
|
||||||
<h3>Multiple Selection with MetaKey</h3>
|
<h3>Multiple Selection with MetaKey</h3>
|
||||||
<Tree :value="nodes" selectionMode="multiple" :selectionKeys.sync="selectedKeys1"></Tree>
|
<Tree :value="nodes" selectionMode="multiple" :selectionKeys.sync="selectedKeys1"></Tree>
|
||||||
{{selectedKeys1}}
|
|
||||||
|
|
||||||
<h3>Multiple Selection without MetaKey</h3>
|
<h3>Multiple Selection without MetaKey</h3>
|
||||||
<Tree :value="nodes" selectionMode="multiple" :selectionKeys.sync="selectedKeys2" :metaKeySelection="false"></Tree>
|
<Tree :value="nodes" selectionMode="multiple" :selectionKeys.sync="selectedKeys2" :metaKeySelection="false"></Tree>
|
||||||
{{selectedKeys2}}
|
|
||||||
|
<h3>Checkbox Selection</h3>
|
||||||
|
<Tree :value="nodes" selectionMode="checkbox" :selectionKeys.sync="selectedKeys3"></Tree>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TreeDoc />
|
<TreeDoc />
|
||||||
|
|
Loading…
Reference in New Issue