AlyssaAlex
AlyssaAlex

Reputation: 716

How can I get display varying number of data elements of a specific attribute in Vue js?

I have a product listing which I am looping on using v-for. These products have headlines and top features. A headline-top feature can look something like this on my webpage:

PRODUCT 1

**First headline**
This is the description of the feature of product 1 under the first headline

**Second headline**
This is the description of the feature of product 1 under the second headline

**Third headline**
This is the description of the feature of product 1 under the third headline

PRODUCT 2

**First headline**
This is the description of the feature of the product 2 under the first headline.

**Second headline**
This is the description of the feature of the product 2 under the second headline.

THE PROBLEM: The number of headline-top feature for each product could vary, like PRODUCT 1 has 3 headline-top feature and PRODUCT 2 has 2 headline-top feature. I am not quite sure how I could specify these varying number of headline-top feature in my Vue app. I have something like this:

Product_listing.vue

<template>
    <div class="content">
        <div class="nested" v-for="product in products">
            <div class="one">{{product.Name}}</div>
              <div class="two"> {{product.headline}}</div>         ---->
                <div class="three"> {{product.top_feature}}</div>  ----> I think I need a loop here? Not sure how?
        </div>
    </div>
</template>

<script>
export default {
  data () {
    return {
        products:[
            {id: 1, Name: 'Product 1', 

             Headline_1:'Headline 1', top_feature_1: 'This is the description of the feature of product 1 under the first headline', 

             Headline_2:'Headline 2', top_feature_2: 'This is the description of the feature of product 1 under the second headline', 

             Headline_3:'Headline 3', top_feature_3: 'This is the description of the feature of product 1 under the third headline'
             },

            {id: 2, Name: 'Product 2', 

             Headline_1:'Headline 1', top_feature_1: 'This is the description of the feature of product 2 under the first headline', 

             Headline_2:'Headline 2', top_feature_2: 'This is the description of the feature of product 2 under the second headline',
             }

            and so on...
        ]


    }
},

  created: function() {
      axios.get('ajaxfile.php')
        .then(function (response) {
          app.products = response.data;
        })
        .catch(function (error) {
          console.log(error);
        });
    }
  }
})
</script>

I would really appreciate some help here. Thanks!

Upvotes: 0

Views: 45

Answers (2)

David Weldon
David Weldon

Reputation: 64332

Assuming the data returned from your axios call has the same shape as the products example, the easiest solution is to reshape the data prior to using it in the template. You can do this using a computed property. Here's a complete working example:

<template>
  <div class="content">
    <div v-for="product in productsWithHeadlines" :key="product.id">
      <div>{{ product.name }}</div>
      <ul>
        <li v-for="(headline, index) in product.headlines" :key="index">
          <div>{{ headline.text }}</div>
          <div>{{ headline.feature }}</div>
        </li>
      </ul>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      products: [
        {
          id: 1,
          Name: 'Product 1',
          Headline_1: 'Headline 1',
          top_feature_1:
            'This is the description of the feature of product 1 under the first headline',
          Headline_2: 'Headline 2',
          top_feature_2:
            'This is the description of the feature of product 1 under the second headline',
          Headline_3: 'Headline 3',
          top_feature_3:
            'This is the description of the feature of product 1 under the third headline',
        },
        {
          id: 2,
          Name: 'Product 2',
          Headline_1: 'Headline 1',
          top_feature_1:
            'This is the description of the feature of product 2 under the first headline',
          Headline_2: 'Headline 2',
          top_feature_2:
            'This is the description of the feature of product 2 under the second headline',
        },
      ],
    };
  },
  computed: {
    // Returns `products` with the following structure:
    // {
    //   id: Number,
    //   name: String,
    //   headlines: [
    //     text: String,
    //     feature: String,
    //   ],
    // }
    productsWithHeadlines() {
      return this.products.map(product => {
        const totalKeys = Object.keys(product).length;
        const headlines = [];
        for (let index = 1; index < totalKeys; index += 1) {
          const text = product[`Headline_${index}`];
          const feature = product[`top_feature_${index}`];
          if (text && feature) headlines.push({ text, feature });
        }

        return {
          id: product.id,
          name: product.Name,
          headlines,
        };
      });
    },
  },
};
</script>

Upvotes: 1

user8282131
user8282131

Reputation: 46

The solution above via reshaping data can solve this problem,and i have easier way to solve it,getting a total keys prior then loop the total keys in the template,and display the fields which have varying number by dynamic.

new Vue({
  el: "#app",
  data: {
    products: [
        {
          id: 1,
          Name: 'Product 1',
          Headline_1: 'Headline 1',
          top_feature_1:
            'This is the description of the feature of product 1 under the first headline',
          Headline_2: 'Headline 2',
          top_feature_2:
            'This is the description of the feature of product 1 under the second headline',
          Headline_3: 'Headline 3',
          top_feature_3:
            'This is the description of the feature of product 1 under the third headline',
        },
        {
          id: 2,
          Name: 'Product 2',
          Headline_1: 'Headline 1',
          top_feature_1:
            'This is the description of the feature of product 2 under the first headline',
          Headline_2: 'Headline 2',
          top_feature_2:
            'This is the description of the feature of product 2 under the second headline',
        },
      ],
  },
  computed: {
    
    
  },
  created(){
  	this.products.map(product => {
        const totalKeys = Object.keys(product).length;
        product.totalKeys = totalKeys
        
      });
    console.log('this.products', this.products)
  },
  methods: {
  	
  }
})
<div id="app">
   <div class="content">
        <div class="nested" v-for="product in products">
            <div class="one">{{product.Name}}</div>
              <div class="two" v-for="num in product.totalKeys">
                <p v-if="product['Headline_'+num]">{{product['Headline_'+num]}}</p>
                <div class="three"> {{product['top_feature_'+num]}}</div>
              </div>         
                
        </div>
    </div>
</div>

<b>https://jsfiddle.net/happy9527/a0rjgp6y/</b>

Upvotes: 1

Related Questions