Use vue.js to add a block of content after every sixth iteration in a loop

Currently, I have a list of offer cards rendering through a loop. I am adding a row div every 3rd column (bootstrap) element. Now, I need to also add another column element (banner block) for every 6th element in order to achieve a layout like the one shown in the following image:

https://i.stack.imgur.com/ugMet.gif

How can I go about implementing this?

Here is my current code:

<div class="row" v-for="i in Math.ceil(offers.length / 3)">
    <div class="col-xl-4 col-lg-4 col-md-6 col-sm-12 col-12" v-for="offer in offers.slice((i-1)*3, i*3)">
        <h2>{{offer.name}}</h2>
        <h2>{{offer.desc}}</h2>
    </div>
</div>

Answer №1

Using a for loop:

    <div class="mycol" v-for="(offer,ind) in offers">
      <template v-if="ind % 5 == 0">
       <h2>banner</banner>
      </template>
      <template v-else>
       <h2>{{offer.name}}</h2>
       <h2>{{offer.desc}}</h2>
      </template>
    </div>

To create a new line for every third column, you can use the following CSS:

.mycol:nth-child(3n+1){
 clear:left;
}

Answer №2

In my opinion, it would be beneficial to shift the focus of your programming from the view to the view model. Consider creating a computed property that organizes your data into groups of offers and banners, as well as rows, and then utilize this computed property in a simple manner.

const chunk = (arr, size) =>
  arr
  .reduce((acc, _, i) =>
    (i % size) ?
    acc :
    [...acc, arr.slice(i, i + size)], []);

new Vue({
  el: '#app',
  data: {
    offers: []
  },
  computed: {
    rows() {
      const withBanners = chunk(this.offers, 5).map((arr) => [...arr, {name: 'banner', type: 'Banner'}]).reduce((a, b) => a.concat(b), []);

      return chunk(withBanners, 3);
    }
  },
  mounted() {
    setTimeout(() => {
      this.offers = [{
          name: 'offer'
        },
        {
          name: 'offer'
        },
        {
          name: 'offer'
        },
        {
          name: 'offer'
        },
        {
          name: 'offer'
        },
        {
          name: 'offer'
        },
        {
          name: 'offer'
        },
        {
          name: 'offer'
        },
        {
          name: 'offer'
        },
        {
          name: 'offer'
        },
        {
          name: 'offer'
        }
      ];
    }, 500);
  }
});
#app {
  display: grid;
}

.row {
  display: grid;
  grid-gap: 2rem;
  grid-template-columns: repeat(3, auto);
  justify-content: left;
}

.box {
  width: 8rem;
  height: 8rem;
}

.banner {
  background-color: #f9c;
}

offer {
  background-color: #99f;
}
<script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
  <div class="row" v-for="row in rows">
    <div class="col-xl-4 col-lg-4 col-md-6 col-sm-12 col-12" v-for="item in row">
      <div v-if="item.type === 'Banner'" class="banner box">
        <h2>{{item.name}}</h2>
      </div>
      <div v-else class="offer box">
        <h2>{{item.name}}</h2>
      </div>
    </div>
  </div>
</div>

Answer №3

This solution will cater to your exact needs. I had to tweak the data a bit because Vue's templating language is not tailored for handling logic in this particular scenario

HTML

<div id="app">
  <div v-for="items in rows" class="row>
    <div v-for="item in items" class="col-xl-4 col-lg-4 col-md-6 col-sm-12 col-12">{{item}}</div>
  </div>
</div>

SCRIPT

created () {
    while (this.items.length > 0) {
      const howMany = (this.rows.length % 3 === 0) ? 3 : 2
      const row = this.items.splice(0, howMany)
      if (howMany === 2) row.push('banner')
      this.rows.push(row)

    }
},

https://jsfiddle.net/jamesharrington/k6c0rgL3/17/

Answer №4

If you're looking to insert a banner every sixth element but display the sixth itself, it might be more efficient to manipulate your data object directly by adding the banner into it. You can achieve this by splitting your array in the following way:

let firstPart = myData.slice(0,5)
let lastPart = myData.slice(5,)

let newData = [...firstPart, banner, ...lastPart]

After implementing this solution, you'll only need to repeat the process every 6 elements.

Answer №5

Using flex is highly recommended if feasible. To implement this, refer to the following code snippet: http://jsfiddle.net/p6yq5mxv/

const app = new Vue({
  el: '#app',
  data() {
    return {
        items: _.times(20, i => ({type: 'offer'})),
    };
  },
  computed: {
    itemsWithBanners() {
      let result = [];
      this.items.forEach((item, idx) => {
        if (idx && idx % 5 === 0) {
            result.push({type: 'banner'});
        }
        result.push(item);
      });
      return result;
    },
  },
});

Answer №6

Appreciate all the help, I implemented Roy J's solution with some modifications for my specific scenario and achieved the desired outcome. Here is my updated code:

<template>
  <div class="section-space80 results-col" >
    <div class="container" >
      <div class="row">
          <div class="col-md-12">
            <div class="wrapper-content bg-white pinside40">
              <div class="row" v-for="row in rows">
                <div v-for="offer in row" class="col-xl-4 col-lg-4 col-md-6 col-sm-12 col-12">
                  <div class="lender-listing" v-if="offer.type && offer.type === 'Banner'">
                    <div class="lender-head">
                        Banner
                    </div>
                  </div>
                  <div class="lender-listing" v-if="offer.mfoName">
                    <div class="lender-head">
                        <div class="lender-logo">Offer</div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
      </div>
    </div>
  </div>
</template>

<script>
  const chunk = (arr, size) =>
  arr
  .reduce((acc, _, i) =>
    (i % size) ?
    acc :
    [...acc, arr.slice(i, i + size)], []);

  import axios from 'axios'
  export default {
    data() {
      return {
        showOffers: true,
        loanOffers: [],
        isVisible: false,
        loadMore: true,
        offset: 0,
        rows: ''

      }
    },

    methods: {
      getOffersList: function () {
        let dataElements = this
        dataElements.loading = true
        axios.get('/api/v1/getUserOffers')
          .then(function (response) {
            dataElements.loanOffers = response.data
            const withBanners = chunk(dataElements.loanOffers, 5).map((arr) => [...arr, {name: 'banner', type: 'Banner'}]).reduce((a, b) => a.concat(b));
            dataElements.rows = chunk(withBanners, 3);
          })
      },
    },
    beforeMount(){
      this.getOffersList()
    }
  }

</script>

Answer №7

A suggestion I have is to utilize a template and iterate through it in a loop. Within the loop, you can check for a condition using v-if="i%6" --> displaying your article, otherwise display your ad with v-else.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tool designed to analyze the timing of sub requests and methods in Node for benchmarking purposes

For my benchmarking and load testing needs, I initially utilized tools such as Apache Bench, Siege, and benchmark.js. However, these tools only provided me with the overall result or time taken from start to finish of the test. I am now seeking a tool or l ...

The v-ripple effect in Vuetify is limited to block-level elements

Today, a new error popped up on my site causing it to break. This happened because I foolishly loaded Vuetify on page load. Is there anyone who knows the meaning of this error and how to fix it? I tried Googling for a solution but couldn't find anyth ...

Is there a way to trigger events on grandchildren in Vue?

I have a hierarchy of components: Class A > Class B > Class C > contain <button/> I am trying to figure out how to pass the updateTest method from Class A as the onClick function for the button in Class C Update 1 ClassA.vue <template& ...

Create compelling visual representations by utilizing Google charts to draw customized charts based on variable

I have been attempting to create a chart using Google Charts by passing some parameters to the function. I am trying to use these parameters to populate the data, but it doesn't seem to be working as expected. Is it possible to include parameters in t ...

Execute computed function after invoking a function in Vue 3

I am experiencing an issue with Vue3 where I want to set data in Vuex and run computed after calling an API. However, the computed function is running before the getProfile function. I have tried using async-await but it does not work (I even used consol ...

Attempting to access a variable without wrapping it in a setTimeout function will

I have a form without any input and my goal is to automatically set the "responsible clerk" field to the currently logged-in user when the component mounts. Here's what I have: <b-form-select v-model="form.responsible_clerk" :op ...

Creating a Reddit-inspired voting system using Laravel 5.3 and VueJS

Currently in the process of learning Vuejs (not too experienced with Laravel), and my goal is to create a basic voting system for various tasks. I've succeeded in adding, editing, and deleting tasks. However, upon implementing the upvote/downvote feat ...

I am having trouble with cookies, as I am unable to retrieve them from my localhost server

Currently, I am in the process of developing a user validation system for my application. However, I have encountered an issue with validating a token as it appears that the necessary cookie is not being retrieved from my browser's storage. Strangely, ...

Vuetify's <v-text-field> feature automatically clears the input after selecting a result from Google Maps autocomplete

A dilemma I'm facing is with a page that has a <v-text-field> containing GoogleMaps autocomplete. The problem arises when Vuetify clears the input once an address is selected by the user. I have discovered that this complication is connected to ...

Utilizing Vue's looping functionality to dynamically insert CSS class names

As a newcomer to Vue, I am facing an issue with handling an array of objects. My goal is to dynamically assign a className to the wrapper of a loop based on a condition. For instance: <div v-for="({time, date, name}, i) in myObject" :key=" ...

JavaScript - Receiving alert - AC_RunActiveContent.js needed for this page to function

When I attempt to open the HTML file in my application, a pop-up message appears stating that "This page requires AC_RunActiveContent.js." However, I have already imported and referenced the AC_RunActiveContent.js file in my package. Can someone assist m ...

Adjust the ZIndex on a div through interactive clicking

For my new project, I'm exploring a concept inspired by Windows 7. The idea is that when you double click on an icon, a window will open. If you keep double clicking on the same icon, multiple windows should appear. The challenge I'm facing is im ...

How to use JQuery to parse an external JSON file with array elements in Javascript

My goal is to extract information from an external JSON file using JavaScript, specifically an array and other elements. The JSON file I am working with is called 'TotalUsers.json' {"@version":"1.0", "@generatedDate":"12/20/10 5:24 PM", "day":[{ ...

Using HTML and JavaScript to create a link that appears as a URL but actually directs to a JavaScript function

I am working on an HTML page and I am trying to create a link that appears to go to 'example.html' but actually goes to 'javascript:ajaxLoad(example.html);'. Here is what I have tried: <a href="example" onclick="javascipt:ajaxLoad( ...

Utilize the power of jQuery to make an ajax request to a PHP backend, expecting a response in JSON format. Then,

Having some trouble with my jQuery code when trying to parse a JSON object returned by PHP and create a list of hyperlinks. Despite receiving the JSON object, my list turns out empty. Can anyone assist me? Below is the jQuery code snippet and the JSON resp ...

Exploring AngularJS: The Innovative Navigation Bar

My goal is to incorporate the functionality demonstrated in this example: https://material.angularjs.org/1.1.1/demo/navBar To achieve this, I have created the following index.html: <!DOCTYPE html> <html lang="en"> <head> &l ...

The issue of why iterating over an array of objects does not function properly in React JS

P.S: I have made some modifications to the code below. Extracting the doctor's value from JSON data, updating the state, and then mapping it to print out the values. Initially, there is only one doctor, but in the future, there could be more than one ...

NodeJS Exporting Features

A situation is in front of me: var express = require('express'); var router = express.Router(); var articles = require('../model/articles.js'); router.get('/all', function(req, res, next) { res.json(articles.getAll()); ...

Is it possible to customize the close icons on the autocomplete feature in Material UI?

Is there a solution to change the icon while keeping its function when clicked? I am looking to replace this Icon <Autocomplete multiple id="checkboxes-tags-demo" options={top100Films} disableCloseOnSelect getOpt ...

JavaScript Simplified Data Sorting after Reduction

I have extracted data from a JSON file and successfully condensed it to show the number of occurrences. Now, my next step is to arrange these occurrences in descending order, starting with the most frequent. To illustrate: var myData = [{ "datapo ...