ProEvilz
ProEvilz

Reputation: 5455

jquery - Inserting element every two loops

I'm trying to wrap a set of images in a div every two loops. Such that every two bootstrap columns are in individual rows. e.g.

<div class="row">
  <div class="col-6"><img src=".."></div>
  <div class="col-6"><img src=".."></div>
</div>

As you can see by this example below, it appears to work when using text.

var data = ["https://via.placeholder.com/100",
  "https://via.placeholder.com/100",
  "https://via.placeholder.com/100",
  "https://via.placeholder.com/100"
];

var output = $('.container');
var i = 0;
$.each(data, function(index, value) {
  var template = '<div class="col-6"><img src=' + value + '></div>';
  if (i % 2 == 0) {
    output.append('<p>ROW START</p.')
  }
  output.append(template)
  i++;
  if (i % 2 == 0) {
    output.append('<p>ROW END</p>')
  }
})
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container"></div>

However, when I use actual divs, they self close automatically resulting in a structure like:

<div class="container">

    <div class="row"></div>

    <div class="col-6"><img src="https://via.placeholder.com/100"></div>
    <div class="col-6"><img src="https://via.placeholder.com/100"></div>

    <div class="row"></div>

    <div class="col-6"><img src="https://via.placeholder.com/100"></div>
    <div class="col-6"><img src="https://via.placeholder.com/100"></div>
</div>

Example snippet:

var data = ["https://via.placeholder.com/100",
  "https://via.placeholder.com/100",
  "https://via.placeholder.com/100",
  "https://via.placeholder.com/100"
];

var output = $('.container');
var i = 0;
$.each(data, function(index, value) {
  var template = '<div class="col-6"><img src=' + value + '></div>';
  if (i % 2 == 0) {
    output.append('<div class="row">')
  }
  output.append(template)
  i++;
  if (i % 2 == 0) {
    output.append('</div>')
  }
})
.row {
min-height:1px;
background:blue;
}

.col-6 {
background:red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
 <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet" />
 <div class="container"></div>

Why do the div tags self close, how can I fix this?

Upvotes: 1

Views: 55

Answers (3)

ziggy wiggy
ziggy wiggy

Reputation: 1067

The DOM is not a string of HTML, so you don't piece together tags that are individually inserted. If you're going to build DOM elements from HTML strings, you need to build the entire element before it's appended. If you try to do it in pieces, a missing closing tag will be automatically corrected, and a lone closing tag will be ignored as invalid input.

Instead, prebuild the entire string, and append it once complete.

var data = ["https://via.placeholder.com/100",
  "https://via.placeholder.com/100",
  "https://via.placeholder.com/100",
  "https://via.placeholder.com/100"
];

var html = data.reduce(function(res, value, i) {
  return res +
    (i % 2 === 0 ? '<div class="row">' : "") +
    ('<div class="col-6"><img src=' + value + '></div>') +
    (i % 2 !== 0 ? '</div>' : "");
}, "");

$('.container').append(html);
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="container">
  <div>

This solution uses .reduce(), since it's built into JS, and designed for this very purpose. The remaining jQuery can be easily eliminated too, taking you a step closer to being free from unnecessary abstraction.

Upvotes: 1

Jason
Jason

Reputation: 696

$.each(data, function(index, value) {
  var template = '<div class="col-6"><img src=' + value + '/></div>';
  if (i % 2 == 0) {
    output.append('<div class="row"></div>')
  }
  $(".row").last().append(template)
  i++;
})

Just append template to the last added row.

https://jsfiddle.net/zL5phyfq/

Upvotes: 2

Alex Kudryashev
Alex Kudryashev

Reputation: 9460

Prepare (build) string content and then append to your output. Something like this.

var data = ["https://via.placeholder.com/100",
  "https://via.placeholder.com/100",
  "https://via.placeholder.com/100",
  "https://via.placeholder.com/100"
];

var output = $('.container');
var i = 0;
var content = '';

$.each(data, function(index, value) {
  var template = '<div class="col-6"><img src=' + value + '></div>';
  if (i % 2 == 0) {
    content += '<div class="row">';
  }
  content += template;
  i++;
  if (i % 2 == 0) {
    content += '</div>';
  }
})
output.append(content);
.row {
  min-height: 1px;
  background: blue;
}

.col-6 {
  background: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet" />
<div class="container"></div>

Upvotes: 2

Related Questions