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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.