I am using the Bootstrap class .clearfix
after every second(or third) <div>
to keep each row starting at the same height on all screen sizes even if two divs on same row have different height.
I use a hidden <div>
at the top as template for information I will get from an ajax call. I have simulated this event in the demo with a button to click and content "insert N" for simplicity. The counter is only there for the demo. In this snippet I also added <br />
to some news to simulate difference in height.
When I insert a <div>
at the top with jquery, I need the .clearfix
classes to move accordingly to keep the current layout, and add a .clearfix
if there are too many <div>
after the last .clearfix
.
The layouts are 1 field on top row, and 2(or 3) fields on all other rows on screen 992px and up, if smaller screen just 1 field per row.
(Just to be clear, when I talk about "row", I do not mean the bootstrap class .row
)
I have managed to get this working with jquery .clone()
/ .prepend()
/ .each()
/ .prev()
/ .next()
/ .insertAfter()
/ .nextUntil()
/ .nextAll()
, but I cant shake the feeling that it is extremely long-winded and hard for next generation coders to maintain. Can anyone offer a cleaner method?
// simulate new content from ajax call
$('#clickit').on('click', function(){
// demo counter
var counter = (parseInt($('#output').text())+1);
$('#output').text(counter); // view
// clone template before filling up with info
var template = $('.modalInputHolder_679');
var templateClone = template.clone();
// remove template-class from old template
// insert new content in new div(old template) and new template
template.removeClass('modalInputHolder_679').text('insert '+counter);
templateClone.text('hidden');
$(".row").prepend(templateClone);
// move clearfix divs up one place
var replaceClass;
var clearfix = $(".row .clearfix");
clearfix.each(function(index){
var that = $(this);
var prev = that.prev();
if(index==0) { // if first .clearfix
replaceClass = that.next().attr('class'); // get new class for old template
prev.attr('class',replaceClass);
}
prev.insertAfter(that); // move up
});
// accomodate for both 1-2 layout and 1-3 layout(wide first, rest split among 2/3 cols)
var clearfixLength = clearfix.length;
if(clearfixLength>1){ // if more than two .clearfix
// find number of divs between clearfixes
var type = clearfix.eq(0).nextUntil('.clearfix').length;
var last = clearfix.eq((clearfixLength-1)); // get last .clearfix
// get number of divs after last
var trailingFields = last.nextAll();
var trailingLength = trailingFields.length;
if(trailingLength>type){ // if difference is more than filled up (2 or 3)
var clearfixClone = clearfix.eq((type-1)).clone(); // create clone of clearfix
trailingFields.eq((type-1)).after(clearfixClone); // input new clearfix
}
}
});
.fullWidthColumn { background-color: #FF0000!important; }
.row>.col-xs-12:nth-of-type(odd) { background-color: #00FF00; }
.row>.col-xs-12:nth-of-type(even) { background-color: #0000FF; }
.modalInputHolder_679 { display:none; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<button class="btn btn-default" id="clickit">Insert news</button> <span> Counter: </span><span id="output">0</span><br />
<div class="container">
<div class="row">
<div class="col-xs-12 fullWidthColumn modalInputHolder_679">hidden</div>
<div class="col-xs-12 fullWidthColumn">first</div>
<div class="clearfix"></div>
<div class="col-xs-12 col-md-6">second<br />...</div>
<div class="col-xs-12 col-md-6">third</div>
<div class="clearfix"></div>
<div class="col-xs-12 col-md-6">fourth</div>
<div class="col-xs-12 col-md-6">fifth<br />...</div>
<div class="clearfix"></div>
<div class="col-xs-12 col-md-6">sixth<br />...</div>
<div class="col-xs-12 col-md-6">seventh</div>
</div>
</div>
Here's jsfiddles of both 2 col layout (code/view) and 3 col layout (code/view), they use the same javascript and css, but slightly different html.
1 Answer 1
Define counter
I'd define a counter like this:
var counter = 0; //I'd define it in upper scope
$('#clickit').on('click', function () {
counter++;
$('#output').text(counter);
Define template:
You defined a template in html, and access and clone it like this:
var template = $('.modalInputHolder_679');
var templateClone = template.clone();
template.removeClass('modalInputHolder_679').text('insert '+counter);
templateClone.text('hidden');
$(".row").prepend(templateClone);
It's verbose. I'd define it like this:
var $row = $('<div class="col-xs-12 fullWidthColumn"></div>')
.text('insert ' + counter);
$(".row").prepend($row);
Since the template is short, you can just define it in js code. If the real template is long, you can define it at somewhere else to avoid handling modalInputHolder_679
things (use the class name on its wrapper).
Type?
var type = clearfix.eq(0).nextUntil('.clearfix').length;
Maybe colCnt
is better. And the .eq(0)
can be replaced with .first()
. Similarly, .eq((clearfixLength - 1));
can be replaced with .last()
.
So this section can be change to:
var last = clearfix.last(); // get last .clearfix
var colCnt = last.prevUntil('.clearfix').length;
Better access
Since you do insertAfter
on every clearfix, why not just insert them again?
var counter = 0; //I'd define it in upper scope
var clearfixTemplate = $('<div class="clearfix"></div>');
var rowTemplate = $('<div class="col-xs-12 fullWidthColumn"></div>');
var rowWrapper = $(".row");
$('#clickit').on('click', function () {
counter++;
$('#output').text(counter);
var clearfix = rowWrapper.find(">.clearfix");
var sections = rowWrapper.find(">.col-xs-12"); //you may need a class name to indicate the `information` element
sections.eq(0).attr("class", sections.eq(1).attr("class"));
if (clearfix.length < 2)
return;
var last = clearfix.last();
var colCnt = last.prevUntil('.clearfix').length;
sections.each(function (index) {
if (index % colCnt === colCnt - 1) {
var clear = clearfix[Math.floor(index / colCnt)]; //reuse them
if (!clear) { //if not enough
clear = clearfixTemplate.clone();
}
$(this).after(clear);
}
});
var row = rowTemplate.clone()
.text('insert ' + counter);
rowWrapper.prepend(row);
});
.fullWidthColumn {
background-color: #FF0000!important;
}
.row>.col-xs-12:nth-of-type(odd) {
background-color: #00FF00;
}
.row>.col-xs-12:nth-of-type(even) {
background-color: #0000FF;
}
.modalInputHolder_679 {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<button class="btn btn-default" id="clickit">Insert news</button> <span> Counter: </span><span id="output">0</span><br />
<div class="container">
<div class="row">
<div class="col-xs-12 fullWidthColumn">first</div>
<div class="col-xs-12 col-md-6">second<br />...</div>
<div class="col-xs-12 col-md-6">third</div>
<div class="clearfix"></div>
<div class="col-xs-12 col-md-6">fourth</div>
<div class="col-xs-12 col-md-6">fifth<br />...</div>
<div class="clearfix"></div>
<div class="col-xs-12 col-md-6">sixth<br />...</div>
<div class="col-xs-12 col-md-6">seventh</div>
</div>
</div>
-
\$\begingroup\$ Thanks for your input and for taking the time to look at it! :) However I can't accept it as the correct answer(yet?) because it does not work as intended anymore. I will make use of some of it, but your full code does not work on large screens. Error1; .col-md-6 / col-md-4 are ignored in your solution. Error2; .clearfix are added but not moved up. Error3; .clearfix are added at the bottom one step too soon. Error4; template is no longer hidden. I have been trying to debug it, but as it created more bugs than solutions, I cant accept this answer. Sorry, and thanks for good ideas \$\endgroup\$turbopipp– turbopipp2017年04月02日 13:15:25 +00:00Commented Apr 2, 2017 at 13:15
-
1\$\begingroup\$ @turbopipp Well.. 1: I can't find col-md-4 in your code. 2: It does, please inspect the result, don't just read the code. 4: the template is not in the document at all. Don't just copy my code to your project, I also changed your html. \$\endgroup\$blackmiaool– blackmiaool2017年04月02日 13:34:18 +00:00Commented Apr 2, 2017 at 13:34
-
\$\begingroup\$ @turbopipp You need
rel="stylesheet"
in your html snippet. \$\endgroup\$blackmiaool– blackmiaool2017年04月02日 13:36:25 +00:00Commented Apr 2, 2017 at 13:36 -
1\$\begingroup\$ @turbopipp It seems that I focused on your stackoverflow snippet and ingored your jsfiddle. I'm sorry for this. \$\endgroup\$blackmiaool– blackmiaool2017年04月02日 13:37:36 +00:00Commented Apr 2, 2017 at 13:37
-
\$\begingroup\$ You are right when it comes to 2 and 4, and 3 doesn't really matter. :) The error was me trying to implement templateID again because the ajax calls could return information to multiple newsfields with different layout, and I had to identify the correct template inside the scope. But you had no way of knowing that was a requirement, so that's on me. :) Thanks for your help, ofc I will accept your answer now. :) \$\endgroup\$turbopipp– turbopipp2017年04月02日 13:55:02 +00:00Commented Apr 2, 2017 at 13:55
Explore related questions
See similar questions with these tags.