title: Render Functions and Recursive Components in Vue
body: <p>I am having some trouble grasping my head around recursive components and I believe for what I am trying to accomplish, this may be the best way of doing so. Here is a Fiddle of where I am at so far, will explain below.</p>
  
  <p><a href="https://jsfiddle.net/wp0hon7z/2/" rel="nofollow noreferrer">https://jsfiddle.net/wp0hon7z/2/</a></p>
  
  <p>I am attempting to traverse through a nested JSON, it essentially mimics a DOM. Each “node” looks like this. You can open the fiddle to see a more nested JSON and</p>
  
  <pre><code>"tagName": "section",
  "classes": ["container", "mx-auto"],
  "attrs": {"id":"main"},
  "textNode": "",
  "children": [{}]
  </code></pre>
  
  <p>Currently I am able to recursively go through and create each node into a component and put them into a Component array which I populate in the Vue Instance.</p>
  
  <p>The issue is, the children components need to be shown inside the parent component. I am thinking maybe create an object with component objects and then use a recursive component to parse these, but I have no idea how to go about it.</p>
  
  <p>The other thought is maybe create a flat array of components with parent ids? And then possible use this somehow?</p>
  
  <p>Some guidance on how to go about this would be great, I think the recursive component will help but not sure how I can use that in addition to the Create Element/Render Functions. Each node will need to have 2 way binding with the class list, attribute list, on, etc. I plan on keeping track of these and editing using states/stores, possibly vuex.</p>
  
  <p>Currently the code seen in the Fiddle will display all the components in the JSON but without nesting, so just one after another.</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>    const jsonData = [
          {
              "tagName": "section",
              "classes": ["container","mx-auto"],
              "attrs": {},
              "textNode": "",
              "children": [
                  {
                     "tagName": "div",
                      "classes": ["flex","flex-wrap"],
                      "attrs": {},
                      "textNode": "",
                      "children": [
                          {
                              "tagName": "div",
                              "classes": ["w-1/2"],
                              "attrs": {},
                              "textNode": "Hello"
                          },
                          {
                              "tagName": "div",
                              "classes": ["w-1/2"],
                              "attrs": {},
                              "textNode": "Goodbye"
                          }
                      ]
                  }
              ]
          }
      ];
  
  
  
      let Components = [];
      let uuid = 0;
   
  
      function recurse() { 
              recursiveInitialize(jsonData)
        
      }
  
   function recursiveInitialize(j) {
  
          
          if (Array.isArray(j)) {
              return j.map((child) =&gt; recursiveInitialize(child))
          }
  
          if (j.children &amp;&amp; j.children.length &gt; 0) {
  
  
               initializeComponent(j)
  
              console.log("Hi I am " + j["tagName"] + " and a parent")
  
  
              j.children.forEach((c) =&gt; {
                  console.log("Hi I am " + c["tagName"] + " and my parent is " + j["tagName"])
                  recursiveInitialize(c)
              });
  
  
          }
  
          else {
              console.log("Hi, I dont have any kids, I am " + j["tagName"])
              initializeComponent(j)
          }
      }
      
  
    function initializeComponent(jsonBlock){
          let tempComponent = {
            name: jsonBlock["tagName"]+ uuid.toString(),
              methods: {
                  greet() {
                      store.setMessageAction(this)
                  }
                },
              data: function() {
                  return {
                      tagName: jsonBlock["tagName"],
                      classes: jsonBlock["classes"],
                      attrs: jsonBlock["attrs"],
                      children: jsonBlock["children"],
                      textNode: jsonBlock["textNode"],
                      on: {click: this.greet},
                      ref: uuid,
                  }
              },
              beforeCreate() {
                  this.uuid = uuid.toString();
                  uuid += 1; 
                  
              
              },
              render: function(createElement) {
                    return createElement(this.tagName, {
                      class: this.classes,
                      on: {
                          click: this.greet
                      },
                      attrs: this.attrs,
                  }, this.textNode);
              },
              mounted() {
                  // example usage
                  console.log('This ID:', this.uuid);
              },
          }
          Components.push(tempComponent);
          return tempComponent
      }
   
      const App = new Vue({
          el: '#app',
  
          data: {
              children: [
                  Components
              ],
          },
          beforeCreate() {
              recurse();
              console.log("recurseRan")
          },
  
          mounted() {
              this.populate()
          },
  
          methods: {
              populate() {
                  let i = 0;
                  let numberOfItems = Components.length;
  
                  for (i = 0; i &lt; numberOfItems; i++) {
                      console.log("populate: " + Components[i])
                      this.children.push(Components[i]);
                  }
  
              },
          }
      });
   </code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"&gt;&lt;/script&gt;
  
  
                          &lt;div id="app"&gt;
                              &lt;template v-for="(child, index) in children"&gt;
                                  &lt;component :is="child" :key="child.name"&gt;&lt;/component&gt;
                              &lt;/template&gt;
                          &lt;/div&gt; </code></pre>
  </div>
  </div>
  </p>