Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vuejs: Dynamic Recursive components (Tree Like Structure)

I am trying to make a custom component that calls the 'list' version of itself. i keep getting an error

Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.

I have included a name option as you can see below but this doesn't solve the problem.

Any idea what it could be?

TestCompList.vue <-- The List component

<template>
    <div>
        <p>I am a list</p>

        <template v-for="block in blocks">
            <test-comp :name="block.name" :header="block.name" :more="block.more" :key="block.id"></test-comp>
        </template>
    </div>
</template>

<script>
import TestComp from './TestComp';
export default {
    name: "TestCompList",
    components: {
        TestComp
    },
    props: ['blocks'],
}
</script>

TestComp.vue <--- The Single component

<template>
    <div>
        <h3>{{header}}</h3>
        <p>{{name}}</p>
        <div class="mr-5" v-if="more">
            <test-comp-list :blocks="more"></test-comp-list>
        </div>
    </div>
</template>

<script>
import TestCompList from './TestCompList';
export default {
    name: "TestComp",
    props: ['header', 'name', 'more'],
    components: {
        TestCompList
    }
}
</script>

Page.vue <-- The page passing the data

<template>
    <div>
       <h3>Testing Recursive components</h3>

       <test-comp-list :blocks="blocks"></test-comp-list>
    </div>
</template>

<script>
import TestCompList from "./TestCompList";
export default {
  components: {
    TestCompList
  },
  data() {
    return {
      blocks: [
        {
          id: 1,
          name: "test1",
          header: "test1Header"
        },
        {
          id: 2,
          name: "test2",
          header: "test2Header"
        },
        {
          id: 3,
          name: "test3",
          header: "test3Header",
          more: [
            {
              id: 4,
              name: "test4",
              header: "test4Header"
            },
            {
              id: 5,
              name: "test5",
              header: "test5Header",
              more: [
                {
                  id: 6,
                  name: "test6",
                  header: "test6Header"
                },
                {
                  id: 7,
                  name: "test7",
                  header: "test7Header"
                }
              ]
            }
          ]
        }
      ]
    };
  }
};
</script>

Any ideas? I solved a similar problem here -> Vuejs: Dynamic Recursive components

But can't seem to apply the solution here. Worst part is sometimes it seems to work and sometimes it doesn't

Help! What could i be missing?

like image 450
Raymond Ativie Avatar asked Feb 15 '18 15:02

Raymond Ativie


People also ask

How to create recursive components in Vue JS?

We can create recursive components in Vue.js and any other framework by following the same mechanics. Imagine a component that must render a tree structure, for example showing a directory tree: We could represent a directory as a Tree, and all subdirectories as a list of Nodes for that tree.

What is traversing a tree in Vue JS?

Traversing a tree is one of them. We can create recursive components in Vue.js and any other framework by following the same mechanics. Imagine a component that must render a tree structure, for example showing a directory tree:

What are the best tree components for Vue JS?

This is a list of 10 best Vue.js tree components that help developers quickly and easily render hierarchical data in a nested tree structure. Have fun. 1. Interactive Tree View For Vue.js 2 – VJstree An interactive tree structure component for Vue.js 2 app. 2. Draggable Nested Tree Component For Vue

What is draggable tree view in Vue JS 2?

Draggable Tree View Component For Vue.js 2 A Vue.js 2 component for creating a draggable tree view where the users are able to re-sort the nodes via drag and drop. 4. Tree Chart Component For Vue.js 2+


2 Answers

You have a circular dependency. Look at the documentation directly below the recursive documentation: Circular References Between Components. You need to add a beforeCreate hook to pull in the child dependency at load time.

This isn't quite the recursive problem that you thought, because if it was recursive, the component would be trying to call itself. Instead it's trying to declare a dependency on a component that, in turn, has a dependency on the component that is trying to declare the dependency; hence the "circular".

Effectively, the vue-loader doesn't know what to do since your dependency graph looks like:

Page -> TestCompList -> TestComp -> TestCompList -> TestComp -> ...

As the docs say, this wouldn't be a problem if you registered these components globally (but then you would have an unnecessarily broad dependency structure). The way to fix this without registering globally, is to have one of the components state it's dependency requirement at runtime in a beforeCreate hook.

New TestCompList.vue

<template>
    <div>
        <p>I am a list</p>

        <template v-for="block in blocks">
            <TestComp :name="block.name" :header="block.name" :more="block.more" :key="block.id"></TestComp>
        </template>
    </div>
</template>

<script>
    export default {
        name: "TestCompList",
        props: ['blocks'],
        beforeCreate: function(){
            this.$options.components.TestComp = require("./TestComp.vue").default;
        }
    }

</script>
like image 184
zero298 Avatar answered Sep 18 '22 00:09

zero298


A more readable approach would be using Webpack’s asynchronous import

All you need to do is changing the components section of TestCompList.vue into this:

        components: {
            TestComp: () => import('./TestComp.vue'),
        }
like image 21
yukashima huksay Avatar answered Sep 18 '22 00:09

yukashima huksay