Skip to content

Instantly share code, notes, and snippets.

@goodjob1114
Forked from plong0/CategoryTree.vue
Created August 20, 2021 17:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save goodjob1114/aa5c2f846622c90cf98dda16102f47c2 to your computer and use it in GitHub Desktop.
Save goodjob1114/aa5c2f846622c90cf98dda16102f47c2 to your computer and use it in GitHub Desktop.
Demo of using single-select Radio Group with Vuetify Treeview
<template>
<v-card>
<v-card-text>
{{ category }}
<radio-tree :items="categories" value-key="id" v-model="category" ref="radioTree"></radio-tree>
</v-card-text>
<v-card-actions>
<v-btn @click.stop="nuke()" color="warning">Nuke</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
import RadioTree from '@/components/RadioTree'
export default {
components: { RadioTree },
data: () => ({
category: null,
categories: [
{
id: 1,
name: '1 Sample Category',
children: [
{ id: 2, name: '1.1 Sample Category' },
{
id: 3,
name: '1.2 Sample Category',
children: [
{ id: 13, name: '1.2.1 Sub-Sampler' },
{ id: 14, name: '1.2.2 Sub-Sampler' },
{ id: 15, name: '1.2.3 Sub-Sampler' }
]
},
{ id: 4, name: '1.3 Sample Category' }
]
},
{
id: 5,
name: '2 Demo Category',
children: [
{ id: 6, name: '2.1 Demo Category' },
{ id: 7, name: '2.2 Demo Category' },
{ id: 8, name: '2.3 Demo Category' },
{ id: 9, name: '2.4 Demo Category' },
{ id: 10, name: '2.5 Demo Category' }
]
},
{
id: 11,
name: '3 Another Category',
children: [
{ id: 12, name: '3.1 Another Child' }
]
}
]
}),
methods: {
nuke (value) {
// remove a targetted value (in this case, it has id: 4)
const removed = this.categories[0].children.splice(2, 1)
if (removed && removed.length && this.category && this.category.id === removed[0].id) {
this.$refs.radioTree.verifySelected()
}
}
}
}
</script>
<style>
</style>
<template>
<v-radio-group
class="radio-tree"
@change="changed"
v-model="input"
:mandatory="false"
>
<v-treeview
:items="items"
@update:open="opened"
dense
shaped
hoverable
>
<template
v-slot:label="{ item }"
>
<v-radio
:label="item.name"
:value="valueFor(item)"
></v-radio>
</template>
</v-treeview>
</v-radio-group>
</template>
<script>
export default {
props: {
items: Array,
valueKey: String,
value: null // accept any type
},
data: () => ({
input: null,
selected: null
}),
methods: {
changed (value) {
if (typeof value !== 'undefined' || !this.findInTree(this.selected)) {
this.selected = this.valueFor(value)
this.$emit('input', this.selected)
}
},
valueFor (value) {
if (this.valueKey && value && typeof value === 'object' && value.hasOwnProperty(this.valueKey)) {
value = value[this.valueKey]
}
return value
},
verifySelected () {
// validate that the selected value is in the tree
// (if parent component removes items, it should use a ref to call this function)
if (this.selected && !this.findInTree(this.selected)) {
this.selected = undefined
this.$emit('input', this.selected)
}
},
findInTree (value, path = '*', key = null, items = null) {
if (!key) {
key = this.valueKey
}
if (!key) {
key = 'id'
}
if (!items) {
items = this.items
}
if (items && items.length) {
if (typeof value === 'object') {
value = value[key]
}
for (let i = 0; i < items.length; i++) {
const item = items[i]
if (!item) {
continue
}
if (item[key] === value) {
return item
}
else if (item.children && item.children.length) {
let checkChildren = true
if (Array.isArray(path)) {
const pathIndex = path.findIndex(check => (check === item[key]))
if (pathIndex !== -1) {
path.splice(pathIndex, 1)
}
else {
checkChildren = false
}
}
if (checkChildren) {
const foundInChild = this.findInTree(value, path, key, item.children)
if (foundInChild) {
return foundInChild
}
}
}
}
}
return null
},
opened (list) {
if (!this.input && this.selected) {
const selected = this.findInTree(this.selected, list)
if (selected) {
this.input = this.valueFor(selected)
}
}
}
}
}
</script>
<style>
.radio-tree {
margin: 0;
}
.radio-tree.v-input--radio-group > .v-input__control {
width: 100%;
}
.radio-tree.v-input--radio-group > .v-input__control > .v-input__slot {
margin: 0;
}
.radio-tree.v-input--radio-group .v-treeview-node__label {
overflow: visible;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment