2

I have some json with below results

{
  "module": [
    {
      "id": 1,
      "title": "Module 1",
      "type": "URL",
      "size": 1,
      "image": "https://localhost/image1.png"
    },
    {
      "id": 2,
      "title": "Module 2",
      "type": "YOUTUBE",
      "size": 2,
      "image": "https://localhost/image2.png"
    }
  ]
}

Now i want to render it on a page with some loop and conditional, like below

<template>
  <section class="page-section homescreen mt-4">
    <div class="container">
        <div class="row">
          <div class="col-lg-3" v-bind:key="data.index" v-for="data in modules" v-if="data.size == 1">
              <img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
          </div>
          <div class="col-lg-6" v-bind:key="data.index" v-for="data in modules" v-if="data.size == 2">
              <img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
          </div>
        </div>
    </div>
  </section>
</template>

<script>
export default {
  data() {
    return {
      modules: [
        {
          "id": 1,
          "title": "Module 1",
          "type": "URL",
          "size": 1,
          "image": "https://localhost/image1.png"
        },
        {
          "id": 2,
          "title": "Module 2",
          "type": "YOUTUBE",
          "size": 2,
          "image": "https://localhost/image2.png"
        }
      ]
    };
  }
};
</script>

But instead of success, i got some error saying

5:99 error The 'modules' variable inside 'v-for' directive should be replaced with a computed property that returns filtered array instead. You should not mix 'v-for' with 'v-if' vue/no-use-v-if-with-v-for
8:99 error The 'modules' variable inside 'v-for' directive should be replaced with a computed property that returns filtered array instead. You should not mix 'v-for' with 'v-if' vue/no-use-v-if-with-v-for

Actually i want to create the <div class="col-lg-3"> part to be dynamic based on the json, if size:1 mean to have col-lg-3 and if size:2 mean to have col-lg-6

Any explanation and suggestion will be appreciated. Thank you

4 Answers 4

4

eslint-plugin-vue was telling you to do this:

<div class="col-lg-3" v-bind:key="data.index" v-for="data in modules.filter(o=>o.size == 1)">
    <img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
</div>
<div class="col-lg-6" v-bind:key="data.index" v-for="data in modules.filter(o=>o.size == 2)">
    <img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
</div>

In your case, it can be simplified as

<div :class="'col-lg-'+data.size*3" v-bind:key="data.index" v-for="data in modules">
    <img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
</div>
Sign up to request clarification or add additional context in comments.

1 Comment

THAT is scalable ! Nice job mate ;)
2

If it's essentially something with css classes, why don't you use v-bind:class or :class with your condition ?

https://v2.vuejs.org/v2/guide/class-and-style.html

But like said in the error message you'll certainly have to create a sub component and then use props on it

https://v2.vuejs.org/v2/guide/components-props.html

Comments

2

In case you have just two sizes:

You can use Computed Properties to achieve this requirement.

First, create two new computed properties like:

computed: {
  modulesSize1: function() {
    return this.modules.filter(x => x.size == 1)
  },
  modulesSize2: function() {
    return this.modules.filter(x => x.size == 2)
  }
}

Now, you can easily loop through computed properties modulesSize1 && modulesSize2 like:

<div class="row">
  <div class="col-lg-3" v-bind:key="data.index" v-for="data in modulesSize1" >
    <img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
  </div>
  <div class="col-lg-6" v-bind:key="data.index" v-for="data in modulesSize2" >
    <img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
  </div>
</div>

In case you have multiple sizes:

First, create a simple method like:

methods: {
  getClass: function(size) {
    return `col-lg-${size * 3}`
  },
}

and then we can update template and use Class Bindings like:

<div :class="getClass(data.size)" :key="data.index" v-for="data in modules">
  <img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
</div>

1 Comment

IMO it's not really scalable, imagine if in a near future he'll have twenty different pictures size ? Will he copy that snippet twenty times ?
1

The v-if is essentially baked in to the v-for (if modules is empty nothing will render) so it's recommended not to use them in combination. If you need it for a separate condition, like you do here, then you'll have to move your v-for on to the <img> itself.

You also won't be able to use data.size this way so you'd have to use something like v-if="modules[0].size == 1" etc.

Edit

@Palash answer is probably the more efficient way to solve this.

Edit 2

@r0ulito and @xianshenglu also makes a really good point, if it's just a class issue, use v-bind.

3 Comments

its not in the image, but in the div, but i will try it anyway.. UPDATE:not possible, can you help me some snippet?
I updated my answer as I missed that you won't be able to use data.size this way
If you could include the data from your axios request i'll make a snippet

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.