I have offers cards list rendering thru the loop. Every 3rd col (bootstrap) elements i add row div. Now i need to add another col element (banner block) for every 6th element. For render some thing like that:
How i can implement that?
My code now
<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>
I have offers cards list rendering thru the loop. Every 3rd col (bootstrap) elements i add row div. Now i need to add another col element (banner block) for every 6th element. For render some thing like that:
How i can implement that?
My code now
<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>
Share
Improve this question
asked Jan 28, 2019 at 19:18
Konstantin RusanovKonstantin Rusanov
6,55411 gold badges43 silver badges56 bronze badges
7 Answers
Reset to default 8for 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>
for new line for every third col you can use css
.mycol:nth-child(3n+1){
clear:left;
}
I would recommend you do less programming in the view and more in the view model. Create a computed
that splits up your data into series of offers and banners, and also into rows, then use that computed in a straightforward way.
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>
This should do exactly what you want.. I had to manipulate the data some because Vue's templating language is not designed to handle the logic for this kind of use case
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/
I assume that you want to add a banner every 6 elemtns, but you want to show the 6th. I would handle this on my data object, inserting the banner inside it. It is easier. You could split your array on this way.
let firstPart = myData.slice(0,5)
let lastPart = myData.slice(5,)
let newData = [...firstPart, banner, ...lastPart]
Now, you just need to do this every 6 elements.
I recommend to use flex if it is possible. So the code will look like: http://jsfiddle.net/n89dbo37/
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;
},
},
});
Thanks for everyone, i took Roy J solution, rebuild for my case and get result. My 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>
I offer to use template and loop over it. Then inside you check v-if="i%6" --> your article v-else --> yuor ad.