Vue 3 - Recursion with Treeview component

Vue 3 - Recursion with Treeview component

Hi welcome back to my Vue series where I share intermediate tips and tricks to use in order to create a view components.

Today, we will focus on building a Treeview Component.
Which looks somewhat like this:

They are very useful il many cases and exists in many different shapes and forms (pun intended). One of my colleague (s/o P.A ) came across the challenge of implementing it using recursion. I am not a stranger to this principle but I never thought about using it through Vue 3. It's a rather useful techniques which forces you to make your component extremely robust because he will call himself and avoid code duplication.

Our Goal

We will do a file explorer which is the most basic application for a Treeview maybe in the whole history of computer. There is lots of different ways in which you can implement it but we are going to see it through recursion.

Coding it

I will try to maintain all of the code of my vue serie inside of this repository. Just switch to the according branch.

Object Structure

We will have a very basic object structure like this:

const fileStructure = {
  name: "src",
  type: "folder",
  children: [
    {
      name: "components",
      type: "folder",
      children: [
        {
          name: "TreeItem.vue",
          type: "file",
        },
        {
          name: "Treeview.vue",
          type: "file",
        },
      ],
    },
    {
      name: "App.vue",
      type: "file",
    },
  ],
};

I have used the basic file structure of our project kind of a structureception if you like.
An Item will have a name which allow it it to identify it and it's unique juste like in a real file explorer. then a type to ensure what we are working with but you could take another approach. We could instead says that if an item doesn't have any children attribute it's a file but this won't cover the empty folders uses cases.
Finally the children attributes that allows us to make the recursion possible.

Treeview Component

<script setup>
defineProps(["fileStructure"]);
</script>

<template>
<ul>
  <li v-for="child in fileStructure.children" :key="child.name">
    <span>{{ child.name }}</span>
    <input type="checkbox" >
    <Treeview v-if="child.type === 'folder'" :fileStructure="child" />
  </li>
</ul>
</template>

This all the code there is to it in order to display our treeview. Notice how simple and concise it is. We define our fileStructure we loop on the children and if the type is folder we call our Component. Since our nested object have the same consistent shape we can call it like this.

Selection

To demonstrate how it simple we will implements selection via a checkbox input juste like this:

<script setup>
defineProps(["fileStructure"]);
const model = defineModel();
function addFileOrFolder(child) {
  if(model.value.includes(child)){
    model.value = model.value.filter((file) => file !== child);
    return;
  }
  model.value =[...model.value , child];
}
</script>

<template>
<ul>
  <li v-for="child in fileStructure.children" :key="child.name">
    <span>{{ child.name }}</span>
    <input type="checkbox" @change="addFileOrFolder(child.name)" >
    <Treeview v-if="child.type === 'folder'" :fileStructure="child" v-model="model" />
  </li>
</ul>
</template>

The same way we call the v-model recursively and add no complexity added. This a voluntary simple example. This acts as a blueprint for more complex system like getting the filepath.

Conclusion

Thanks for reading this far I hope this will give your inspiration for components implementation.Here is the fully working demo. See you next time!

Did you find this article valuable?

Support nass.bin by becoming a sponsor. Any amount is appreciated!