Home > OS >  How to use v-for to render an array of dynamic components in vuejs?
How to use v-for to render an array of dynamic components in vuejs?

Time:08-13

I have a page where a user gets to decide between different products, here is the list in my View page:

items: [
        {
          id: 1,
          name: "Product_1",
          children: [
            { name: "Order", id: "62c40e2faba699b309005102", popup: "order" },
            { name: "Feedback", id: "62c40e26aba699b309005100", popup: "feedback" },
          ],
        },
        {
          id: 2,
          name: "Product_2",
          children: [
            { name: "Pre-Order", id: "62c404228ce80aac470a1339", popup: "preOrder"},
          ],
        },

When they do, different form block components should appear in a popup, here is the list of the different combinations in a different file:

computed: {
    order(){
      return [
        {name : "personal info" , component:"PersonalInfo"},
        {name : "credit card" , component:"CreditCard"},

      ]
    feedback(){
      return [
        {name : "personal info" , component:"PersonalInfo"},
        {name : "feedback text" , component:"FeedbackText"},

      ]
    preOrder(){
      return [
        {name : "email" , component:"Email"},
        {name : "order details" , component:"OrderDetails"},

      ]
},

So if they want to order product one: they should see the form popups asking them to enter personal info and credit card info,

if they want to give feedback to product 1: they should see the form popups asking them to enter personal info and feedback input text,

if they want to order product 2, they can only preorder it yet so they should enter their email info and give details about the preorder.

When I hard code one of the keys like this, it works, and I have the 2 components called by feedback() that render.

<li v-for="item in feedback" v-bind:key="item.name">
    <span >{{item.name}}</span>
       <component :is="item.component"  />
</li>

However, when I try to change the v-for for a dynamic value that changes based on which product the user clicks on, I get an error (says popup is not defined). :

<li v-for="item in items.children.popup" v-bind:key="item.name">
    <span >{{item.name}}</span>
       <component :is="item.component"  />
</li>

The items are passed as a prop from the parent page to the child component like this:

in parent:
<popUps
      v-if="show"
      :show="show"
      :items="items"
      @close="show = false"
    ></popUps>

in child: 
props: ["show", "items"],

So I'm not sure how to write the v-for part to access the functions order(), feedback() or preorder() and then render the component accordingly.

CodePudding user response:

The mistake is made when you've tried to loop on 'item.children.popup', which is undefined (item.children is an array and not an object). You should update your code like that :

1 - Put your computed variables in one computed variable called componentsDeclaration :

computed: {
    componentsDeclaration(){
      return { 
          order : [
               {name : "personal info" , component:"PersonalInfo"},
               {name : "credit card" , component:"CreditCard"},
          ],
          feedback : [
               {name : "personal info" , component:"PersonalInfo"},
               {name : "feedback text" , component:"FeedbackText"},
          ],
          preOrder : [
               {name : "email" , component:"Email"},
               {name : "order details" , component:"OrderDetails"},
          ]
      }
    }
},

2 - Access to the popup content by using 'componentsDeclaration' :

<li v-for="item in items.children" v-bind:key="item.name">
    <div v-for="subItem in componentsDeclaration[item.popup] v-bind:key="subItem.name">
           <span >{{subItem.name}}</span>
           <component :is="subItem.component"  />
    </div>
</li>
  • Related