5

Here is my vue layout:

<template lang="pug">
  .row
    .col-4(v-for="article in articles") // need to render 1-3 items here
      | {{ article.name }}
  .row
    .col-4(v-for="article in articles") // need to render 4-6 items here
      | {{ article.name }}
</template>

<script>
export default {
  name: 'Articles',
  data() {
    return {
      articles: [
        { name: 'Article 1' },
        { name: 'Article 2' },
        { name: 'Article 3' },
        { name: 'Article 4' },
        { name: 'Article 5' },
        { name: 'Article 6' },
      ]
    }
  },
}
</script>

The Goal is:

<div class="row">
  <div class="col-4">article[0].name</div>
  <div class="col-4">article[1].name</div>
  <div class="col-4">article[2].name</div>
</div>

<div class="row">
  <div class="col-4">article[3].name</div>
  <div class="col-4">article[4].name</div>
  <div class="col-4">article[5].name</div>
</div>

In Python based Micro Framework like Flask and Jinja, it's possible to do in this way:

{% for article_row in articles | batch(3, '&nbsp;') %}
  <div class="row">
    {% for article in article_row %}
    <div class="span4">{{ article }}</div>
    {% endfor %}
  </div>
{% endfor %}

So, is there a way to do like above in vue.js?

1
  • 1
    You can replicate the batch behaviour in JavaScript. Just have a computed value that turns the 1D array into 2D array (see stackoverflow.com/a/22464838 for an example) and then have 2 v-for loops Commented Apr 26, 2018 at 8:25

6 Answers 6

10

I would use helper groups array to render groups of articles in rows:

<template lang="pug">
  .container
    .row(v-for="(group, i) in articleGroups")
      .col-4(v-for="article in articles.slice(i * itemsPerRow, (i + 1) * itemsPerRow)")
        | {{ article.name }}
</template>

<script>
export default {
  name: 'Articles',
  data() {
    return {
      itemsPerRow: 3,
      articles: [
        { name: 'Article 1' },
        { name: 'Article 2' },
        { name: 'Article 3' },
        { name: 'Article 4' },
        { name: 'Article 5' },
        { name: 'Article 6' },
      ]
    }
  },
  computed: {
    articleGroups () {
      return Array.from(Array(Math.ceil(this.articles.length / this.itemsPerRow)).keys())
    }
  },
}
</script>

Demo: https://codesandbox.io/s/rj60o8l5p

Sign up to request clarification or add additional context in comments.

2 Comments

I forked your project so it does not rely on array handling or slicing using v-for with a range: codesandbox.io/s/4086n4o5j9
Added another sandbox example with the (vue/require-v-for-key) requirement and a helper method for the active article where it's used multiple times. Is there a better way? codesandbox.io/s/vue-template-yy169?file=/src/components/…
10

I'd use a computed property to chunk them up. If you have lodash available you can do:

computed: {
  chunked () {
    return _.chunk(this.articles, 3)
  },
},

You can find the logic for chunking all over the place if you don't have lodash around this will work.

function chunk (arr, len) {

  const chunks = []
  const i = 0
  const n = arr.length

  while (i < n) {
    chunks.push(arr.slice(i, i += len))
  }

  return chunks
}

Then, you can do:

<div class="row" v-for="chunk in chunked">
  <div class="col-4" v-for="article in chunk">
    {{ article.name }}
  </div>
</div>

Comments

3

a combination of v-for="(article,i) in articles" and v-if="i>=0 && i<3"

Comments

1

Using .reduce you can break your array into groups of X.

<template>
    <div class="container">
        <template v-for="group in groupedArticles">
            <div class="row">
                <span v-for="article in group">
                    {{ article.title }}
                </span>
            </div>
        </template>
    </div>
</template>

<script>
    export default {
        data: function() {
            return {
                articles: [
                    { id: 1, title: 'Hello People' },
                    { id: 2, title: 'What Time is it?' },
                    { id: 3, title: 'Dogs & Cats' }
                ],
                itemsPerRow: 2
            }
        },
        computed: {
            groupedArticles: function() {
                return this.articles.reduce((accumulator, article, index) => {
                    if (index % this.itemsPerRow == 0) {
                        accumulator.push([article]);
                    } else {
                        accumulator[accumulator.length - 1].push(article);
                    } 

                    return accumulator;
                }, []);
            }
        },
    }
</script>

Comments

1

The simpler way to use lodash.chunk() function in your code is:

<template lang="pug">
  .row(v-for="column in articles")
    .col-4(v-for="article in column") 
      | {{ article.name }}
</template>

<script>
import lodash from "lodash"

export default {
  name: 'Articles',
  data() {
    return {
      articles: lodash.chunk([
        { name: 'Article 1' },
        { name: 'Article 2' },
        { name: 'Article 3' },
        { name: 'Article 4' },
        { name: 'Article 5' },
        { name: 'Article 6' },
      ], 3),
    }
  },
}
</script>

Refer here for a detailed explanation of lodash.chunk() function: https://dustinpfister.github.io/2017/09/13/lodash-chunk/

Comments

0

For Vue 3 you can do it this way:

  1. install lodash to split the array/object into chunks:

    npm i lodash

  2. Import the lodash and use in the vue component as below:

<script setup>
    import _ from "lodash";

    const ObjecVariableHere = {
    {name: 'example'},{name: 'example2'},{name: 'example3'},{name: 'example4'},{name: 'example5'},{name: 'example6'},{name: 'example7'},{name: 'example8'},{name: 'example9'},{name: 'example10'},{name: 'example11'},{name: 'example12'},
    };

    const chunk = (objOrArr, numberColumns) => {
        return _.chunk(objOrArr, numberColumns);
    };
</script>
<template>
    <div class="card card-body rounded-lg shadow-none border-light w-100">
        <div v-for="(group,index) in chunk(ObjecVariableHere,4)" :key="index" class="row">
            <div v-for="(item,subindex) in group" class="col-md-3 mb-3">
                <ul>
                    <li>group: {{index}} - item: {{subindex}}</li>
                </ul>
            </div>
        </div>
    </div>
</template>

*The example above uses bootstrap design, but it is not essential. *If you click on "Run code snippet" nothing will happen because it's not supported, but it should work in your Vue3 project.

Comments

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.