Skip to content

Node Manipulation

Custom Node

There are two ways of customizing nodes:

  1. Use named slot node
  2. Use render prop
Show code
vue
<template>
  <VTree :data="data">
    <template #node="{ node }">
      <span :style="{ color: 'violet' }">{{ node.title }}</span>
    </template>
  </VTree>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import VTree from '@wsfe/vue-tree'

const data = ref([
  {
    title: 'node-1',
    id: 'node-1',
    children: [
      {
        title: 'node-1-1',
        id: 'node-1-1',
        children: [
          {
            title: 'node-1-1-1',
            id: 'node-1-1-1',
          },
          {
            title: 'node-1-1-2',
            id: 'node-1-1-2',
          },
          {
            title: 'node-1-1-3',
            id: 'node-1-1-3',
          },
        ],
      },
      {
        title: 'node-1-2',
        id: 'node-1-2',
        children: [
          {
            title: 'node-1-2-1',
            id: 'node-1-2-1',
          },
          {
            title: 'node-1-2-2',
            id: 'node-1-2-2',
          },
        ],
      },
      {
        title: 'node-1-3',
        id: 'node-1-3',
        children: [
          {
            title: 'node-1-3-1',
            id: 'node-1-3-1',
          },
          {
            title: 'node-1-3-2',
            id: 'node-1-3-2',
          },
        ],
      },
    ],
  },
  {
    title: 'node-2',
    id: 'node-2',
    children: [
      {
        title: 'node-2-1',
        id: 'node-2-1',
        children: [
          {
            title: 'node-2-1-1',
            id: 'node-2-1-1',
          },
          {
            title: 'node-2-1-2',
            id: 'node-2-1-2',
          },
        ],
      },
    ],
  },
])
</script>

Drag and Drop

Enable draggable and droppable

Show code
vue
<template>
  <VTree :data="data" checkable draggable droppable />
</template>

<script setup lang="ts">
import { ref } from 'vue'
import VTree from '@wsfe/vue-tree'

const data = ref([
  {
    title: 'node-1',
    id: 'node-1',
    children: [
      {
        title: 'node-1-1',
        id: 'node-1-1',
        children: [
          {
            title: 'node-1-1-1',
            id: 'node-1-1-1',
          },
          {
            title: 'node-1-1-2',
            id: 'node-1-1-2',
          },
          {
            title: 'node-1-1-3',
            id: 'node-1-1-3',
          },
        ],
      },
      {
        title: 'node-1-2',
        id: 'node-1-2',
        children: [
          {
            title: 'node-1-2-1',
            id: 'node-1-2-1',
          },
          {
            title: 'node-1-2-2',
            id: 'node-1-2-2',
          },
        ],
      },
      {
        title: 'node-1-3',
        id: 'node-1-3',
        children: [
          {
            title: 'node-1-3-1',
            id: 'node-1-3-1',
          },
          {
            title: 'node-1-3-2',
            id: 'node-1-3-2',
          },
        ],
      },
    ],
  },
  {
    title: 'node-2',
    id: 'node-2',
    children: [
      {
        title: 'node-2-1',
        id: 'node-2-1',
        children: [
          {
            title: 'node-2-1-1',
            id: 'node-2-1-1',
          },
          {
            title: 'node-2-1-2',
            id: 'node-2-1-2',
          },
        ],
      },
    ],
  },
])
</script>

Node Creation and Removal

  • Invoke insertBefore, insertAfter method of tree component to insert new node before and after tree nodes
  • Invoke prepend, append method of tree component to prepend or append to child list
  • Invoke remove to remove a node
Show code
vue
<template>
  <VTree ref="tree" :data="data">
    <template #node="{ node }">
      <span>{{ node.title }}</span>
      <button @click="handleAdd(node)">Add sibling</button>
      <button @click="handleAppend(node)">Append child</button>
      <button @click="handleRemove(node)">Remove</button>
    </template>
  </VTree>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import VTree from '@wsfe/vue-tree'

const tree = ref()

let nodeAddCount = 0
let nodeAppendCount = 0

const handleAdd = (node) => {
  tree.value.insertAfter({ title: `node-added-${nodeAddCount}` }, node.id)
  nodeAddCount++
}

const handleAppend = (node) => {
  tree.value.append({ title: `node-appended-${nodeAppendCount}` }, node.id)
  nodeAppendCount++
}

const handleRemove = (node) => {
  tree.value.remove(node.id)
}

const data = ref([
  {
    title: 'node-1',
    id: 'node-1',
    children: [
      {
        title: 'node-1-1',
        id: 'node-1-1',
        children: [
          {
            title: 'node-1-1-1',
            id: 'node-1-1-1',
          },
          {
            title: 'node-1-1-2',
            id: 'node-1-1-2',
          },
          {
            title: 'node-1-1-3',
            id: 'node-1-1-3',
          },
        ],
      },
      {
        title: 'node-1-2',
        id: 'node-1-2',
        children: [
          {
            title: 'node-1-2-1',
            id: 'node-1-2-1',
          },
          {
            title: 'node-1-2-2',
            id: 'node-1-2-2',
          },
        ],
      },
      {
        title: 'node-1-3',
        id: 'node-1-3',
        children: [
          {
            title: 'node-1-3-1',
            id: 'node-1-3-1',
          },
          {
            title: 'node-1-3-2',
            id: 'node-1-3-2',
          },
        ],
      },
    ],
  },
  {
    title: 'node-2',
    id: 'node-2',
    children: [
      {
        title: 'node-2-1',
        id: 'node-2-1',
        children: [
          {
            title: 'node-2-1-1',
            id: 'node-2-1-1',
          },
          {
            title: 'node-2-1-2',
            id: 'node-2-1-2',
          },
        ],
      },
    ],
  },
])
</script>

<style scoped>
button {
  margin-left: 8px;
  border: 1px solid lightgray;
  border-radius: 4px;
  padding: 0 4px;
  font-size: 12px;
  line-height: 12px;
  height: 20px;
}
</style>

Update Node Title

Invoke updateNode method to update some fields of tree node

Invoke updateNodes to update multiple nodes

Show code
vue
<template>
  <button @click="handleUpdateSingleNode">Update node-1</button>
  <button @click="handleUpdateMultipleNode">Update node-1 & node-2</button>
  <VTree ref="tree" />
</template>

<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import VTree from '@wsfe/vue-tree'

const tree = ref()

const data = [
  {
    title: 'node-1',
    id: 'node-1',
    children: [
      {
        title: 'node-1-1',
        id: 'node-1-1',
      },
      {
        title: 'node-1-2',
        id: 'node-1-2',
      },
    ],
  },
  {
    title: 'node-2',
    id: 'node-2',
    children: [
      {
        title: 'node-2-1',
        id: 'node-2-1',
      },
    ],
  },
]

onMounted(() => {
  tree.value.setData(data)
})

const count = ref(0)

const handleUpdateSingleNode = () => {
  count.value++
  tree.value.updateNode('node-1', { title: `node-1 - ${count.value}` })
}
const handleUpdateMultipleNode = () => {
  count.value++
  tree.value.updateNodes([
    {
      id: 'node-1',
      title: `node-1 - ${count.value}`,
    },
    {
      id: 'node-2',
      title: `node-2 - ${count.value}`,
    },
  ])
}
</script>

<style scoped>
button {
  border: 1px solid lightgray;
  border-radius: 8px;
  padding-left: 10px;
  padding-right: 10px;
  margin-right: 20px;
}
</style>

Update Custom Field

Invoke updateNode method to update custom fields in tree node

Show code
vue
<template>
  <button @click="handleUpdateCount">Update node-1 count</button>
  <VTree ref="tree">
    <template #node="{ node }">
      <span>{{ node.title }}</span>
      <span v-if="typeof node.count === 'number'">
        Count: {{ node.count }}
      </span>
    </template>
  </VTree>
</template>

<script setup lang="ts">
import { onMounted, ref } from 'vue'
import VTree from '@wsfe/vue-tree'

const tree = ref()

const data = [
  {
    title: 'node-1',
    id: 'node-1',
    count: 0,
    children: [
      {
        title: 'node-1-1',
        id: 'node-1-1',
      },
      {
        title: 'node-1-2',
        id: 'node-1-2',
      },
    ],
  },
  {
    title: 'node-2',
    id: 'node-2',
    children: [
      {
        title: 'node-2-1',
        id: 'node-2-1',
      },
    ],
  },
]

onMounted(() => {
  tree.value.setData(data)
})

const handleUpdateCount = () => {
  const key = 'node-1'
  const currentCount = tree.value.getNode(key).count
  tree.value.updateNode(key, { count: currentCount + 1 })
}
</script>

<style scoped>
button {
  border: 1px solid lightgray;
  border-radius: 8px;
  padding-left: 10px;
  padding-right: 10px;
  margin-right: 20px;
}
</style>

Reload Child Nodes

Invoke updateNode and pass a new children list to reload child nodes

Show code
vue
<template>
  <button @click="handleClearChildren">Clear node-1 children</button>
  <button @click="handleSetChildren">Set node-1 children</button>
  <button @click="handleUpdateChildren">Update node-1 children</button>
  <div :style="{ height: '300px' }">
    <VTree ref="tree" checkable selectable />
  </div>
</template>

<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import VTree from '@wsfe/vue-tree'

const tree = ref()

const children = Array.from({ length: 100000 }).map((_, i) => {
  return {
    title: `node-1-${i + 1}`,
    id: `node-1-${i + 1}`,
  }
})

const data = [
  {
    title: 'node-1',
    id: 'node-1',
    children,
  },
  {
    title: 'node-2',
    id: 'node-2',
    children: [
      {
        title: 'node-2-1',
        id: 'node-2-1',
      },
    ],
  },
]

onMounted(() => {
  tree.value.setData(data)
})

const handleSetChildren = () => {
  tree.value.updateNode('node-1', { children })
}
const handleClearChildren = () => {
  tree.value.updateNode('node-1', { children: [] })
}
const handleUpdateChildren = () => {
  tree.value.updateNode('node-1', {
    children: children.map((child) => {
      return {
        ...child,
        title: `${child.title} ${Date.now()}`,
        checked: true,
      }
    })
  })
}
</script>

<style scoped>
button {
  border: 1px solid lightgray;
  border-radius: 8px;
  padding-left: 10px;
  padding-right: 10px;
  margin-right: 20px;
}
</style>