0

I am using Bootstrap5 and VueJS 2 and trying to create a "pinterest-style" cards layout like shown in this screenshot:

enter image description here

The above layout example requires the following HTML markup: [Codesandbox available]

<main>
    <div class="container-fluid">
        <div class="row">
           <div class="col-md-9">
                <div class="row">
                      <div class="col-md-4">
                        <article>
                        </article>
                        <article>
                        </article>
                      </div>
                      <div class="col-md-4">
                        <article>
                        </article>
                        <article>
                        </article>
                      </div>
                      <div class="col-md-4">
                        <article>
                        </article>
                        <article>
                        </article>
                      </div>
           </div>
        <aside class="col-md-3 ml-auto">
           ...sidebar content...
        </aside>
        </div>
    </div>
</main>

Using JavaScript, how can I take the data array and return 3 new arrays with equal amounts of items in each array except for the last array ? This way I can properly scaffold the layout with an output like shown in the above screenshot? So, for example, if I had a source data array of [1,2,3,4,5,6,7,8,9,10,11], I would like to return something like [ [1,2,3,4], [5,6,7,8], [9,10,11] ]

I have an initial attempt at this (in VueJS) but I obviously did not do it correctly because although I got the layout sort of to work, the order was wrong and there were gaps beneath some of the cards. I am afraid my JavaScript knowledge is mediocre. My attempt: https://codesandbox.io/s/vue-bootstrap-card-layout-0xjlt?file=/src/App.vue

redshift
  • 4,815
  • 13
  • 75
  • 138
  • this might be useful: https://stackoverflow.com/questions/8495687/split-array-into-chunks – GrafiCode Aug 25 '21 at 15:55
  • tried something like that, but how to specify that i want to return just 3 sub arrays? – redshift Aug 25 '21 at 15:57
  • Take a look at this `_.chunk()` in lodash, it does exactly what you want https://lodash.com/docs/4.17.15#chunk – Adil Bimzagh Aug 25 '21 at 16:02
  • you can determine the size of `chunk` dividing `array.length` by 3 and ceiling the result: `chunk = Math.ceil( array.length / 3);` – GrafiCode Aug 25 '21 at 16:08
  • @AdilBimzagh : Thanks, you are correct. Any reason to use Lodash library instead of the posted answer below? – redshift Aug 25 '21 at 16:39
  • If you care about performance and you don't want to waste time creating/testing utility functions then I recommend using lodash. – Adil Bimzagh Aug 25 '21 at 16:51

2 Answers2

3

You were very close, but to get the correct number of chunks divide and get the ceiling of the number of items by the desired number of columns...

Math.ceil(this.mockData.length / 3)
  computed: {
    chunkArray() {
      let result = [];
      const size = Math.ceil(this.mockData.length / 3);
      for (let i = 0; i < this.mockData.length; i += size) {
        let chunk = this.mockData.slice(i, i + size);
        result.push(chunk);
      }
      return result;
    },
  },

Codesandbox

Carol Skelly
  • 351,302
  • 90
  • 710
  • 624
  • Thanks! This does answer my question and I will mark it as "solved", but one thing I did not account for was the ordering. The order is now vertical. Possible to make it horizontal? – redshift Aug 25 '21 at 17:00
1

If you want the order to be "horizontal" such as:

[[1, 4, 7, 10], [2, 5, 8, 11], [3, 6, 9]]

Then a slightly different approach is needed. You just loop through the items pushing each into the appropriate sub-array (much like dealing a deck of playing cards to three people).

computed: {
  chunkArray() {
    let result = [];
    const cols = 3;
    this.mockData.forEach((item, index) => {
      let i = index;
      // determine the index of the destination sub-array 
      while (i >= cols) {
        i -= cols; // i will be 0, 1, or 2
      }
      // create the sub-array if needed
      if (!Array.isArray(result[i])) {
        result[i] = [];
      }
      // put the item in the sub-array
      result[i].push(item);
    })

    return result;
  },
},

https://codesandbox.io/s/vue-bootstrap-card-layout-forked-cj0w1?file=/src/App.vue:7492-7847

Arleigh Hix
  • 9,990
  • 1
  • 14
  • 31
  • This grid tier works great for medium breakpoints and higher. However, for small screens with single column view, the ordering is random. Is it possible to order the array items back to [1, 2, 3, 4, 5, 6....etc] which is essentially @zim's answer above? I can make a new question for this, just wondering if it's first possible. Thanks! – redshift Aug 28 '21 at 19:54