Skip to content

Instantly share code, notes, and snippets.

@felipyamorim
Forked from plong0/CategoryTree.vue
Created May 5, 2021 22:27
Show Gist options
  • Select an option

  • Save felipyamorim/5a546f74d4c48d1ce253fe9c62af5dce to your computer and use it in GitHub Desktop.

Select an option

Save felipyamorim/5a546f74d4c48d1ce253fe9c62af5dce to your computer and use it in GitHub Desktop.

Revisions

  1. @plong0 plong0 revised this gist Jan 11, 2020. No changes.
  2. @plong0 plong0 revised this gist Jan 11, 2020. 2 changed files with 20 additions and 6 deletions.
    2 changes: 1 addition & 1 deletion CategoryTree.vue
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@
    <v-card>
    <v-card-text>
    {{ category }}
    <radio-tree :items="categories" v-model="category" ref="radioTree"></radio-tree>
    <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>
    24 changes: 19 additions & 5 deletions RadioTree.vue
    Original file line number Diff line number Diff line change
    @@ -17,7 +17,7 @@
    >
    <v-radio
    :label="item.name"
    :value="item"
    :value="valueFor(item)"
    ></v-radio>
    </template>
    </v-treeview>
    @@ -27,6 +27,7 @@
    export default {
    props: {
    items: Array,
    valueKey: String,
    value: null // accept any type
    },
    data: () => ({
    @@ -36,10 +37,16 @@ export default {
    methods: {
    changed (value) {
    if (typeof value !== 'undefined' || !this.findInTree(this.selected)) {
    this.selected = value
    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)
    @@ -48,7 +55,13 @@ export default {
    this.$emit('input', this.selected)
    }
    },
    findInTree (value, path = '*', key = 'id', items = null) {
    findInTree (value, path = '*', key = null, items = null) {
    if (!key) {
    key = this.valueKey
    }
    if (!key) {
    key = 'id'
    }
    if (!items) {
    items = this.items
    }
    @@ -88,8 +101,9 @@ export default {
    },
    opened (list) {
    if (!this.input && this.selected) {
    if (this.findInTree(this.selected, list)){
    this.input = this.selected
    const selected = this.findInTree(this.selected, list)
    if (selected) {
    this.input = this.valueFor(selected)
    }
    }
    }
  3. @plong0 plong0 renamed this gist Jan 5, 2020. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  4. @plong0 plong0 created this gist Jan 5, 2020.
    112 changes: 112 additions & 0 deletions RadioTree.vue
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,112 @@
    <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="item"
    ></v-radio>
    </template>
    </v-treeview>
    </v-radio-group>
    </template>
    <script>
    export default {
    props: {
    items: Array,
    value: null // accept any type
    },
    data: () => ({
    input: null,
    selected: null
    }),
    methods: {
    changed (value) {
    if (typeof value !== 'undefined' || !this.findInTree(this.selected)) {
    this.selected = value
    this.$emit('input', this.selected)
    }
    },
    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 = 'id', items = null) {
    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) {
    if (this.findInTree(this.selected, list)){
    this.input = this.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>
    68 changes: 68 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,68 @@
    <template>
    <v-card>
    <v-card-text>
    {{ category }}
    <radio-tree :items="categories" 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>