I have several divs that have the same class .timeline-travel-steps
. These divs contain elements .step
that I want to select with jQuery each()
Method
HTML
<div class="timeline-graphic">
<div class="step"></div>
<div class="step"></div>
<div class="step"></div>
</div>
<div class="timeline-graphic">
<div class="step"></div>
<div class="step"></div>
<div class="step"></div>
<div class="step"></div>
<div class="step"></div>
<div class="step"></div>
</div>
JS (jQuery)
var i = 0;
$(".timeline-graphic .step").each(function(index, value) {
$(this).css('left', i + 'px');
i = i + 20;
});
It works but I need to know when the each()
reaches the end of a div timeline-travel-steps
. Currently the each()
continues and run the elements contained in the other divs. It would be very simple if each divs had a different and static class but these divs are generated by a cms and I don't know how many there are.
I need something like:
if (isLastElement) {
i = 0;
}
I've tried to play with index
and .length
but the each()
continues to run.
Here is a snippet
var i = 0; $(".timeline-graphic.step").each(function(index, value) { //console.log(index); var numItems = $(this).parent().length; console.log(numItems); $(this).css('left', i + 'px'); i = i + 20; });
.timeline-graphic { height: 4px; background-color: #000; border-radius: 0.25rem; margin: 0 auto 80px auto; width: 100%; position: relative; }.step { position: absolute; top: -3px; width: 11px; height: 11px; background-color: red; border-radius: 50%; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div class="timeline-graphic"> <div class="step"></div> <div class="step"></div> <div class="step"></div> </div> <div class="timeline-graphic"> <div class="step"></div> <div class="step"></div> <div class="step"></div> <div class="step"></div> <div class="step"></div> <div class="step"></div> </div>
If you use each along with the index
argument there is no need to use another counter variable. Just cycle all .step
elements for each .timeline-graphic
element
$('.timeline-graphic').each(function() {
$('.step', this).each(function(index, v) {
console.log(index);
$(this).css('left', (index * 20) + 'px');
});
})
As a side note there is no even need to use jQuery
and/or position: absolute
for this kind of task when you can use use only CSS
, by adjusting the distance of the dots inside a Flexbox
container with the gap
property:
.timeline-graphic { display: flex; align-items: center; gap: 20px; height: 2rem; background: linear-gradient(to bottom, transparent 0, transparent calc(50% - 2px), #000 0, #000 calc(50% + 2px), transparent 0 ) repeat-x; }.step { border-radius: 50%; height: 50%; aspect-ratio: 1; background: red; }
<div class="timeline-graphic"> <div class="step"></div> <div class="step"></div> <div class="step"></div> <div class="step"></div> <div class="step"></div> <div class="step"></div> </div> <div class="timeline-graphic"> <div class="step"></div> <div class="step"></div> <div class="step"></div> </div>
In case the distance of the dots were determined by JavaScript, you could still go with the CSS solution and use JS to just update a custom variable, eg
:root { --gap: 0; }.timeline-graphic { display: flex; align-items: center; gap: var(--gap); height: 2rem; background: linear-gradient(to bottom, transparent 0, transparent calc(50% - 2px), #000 0, #000 calc(50% + 2px), transparent 0 ) repeat-x; }.step { border-radius: 50%; height: 50%; aspect-ratio: 1; background: red; }
<label for="gap" id="gap-label">Adjust the gap via JS</label> <input type="range" id="gap" aria-labelledby="gap-label" min="0" max="40" step="1" value="0" oninput="document.documentElement.style.setProperty('--gap', this.value + 'px');" /> <hr /> <div class="timeline-graphic"> <div class="step"></div> <div class="step"></div> <div class="step"></div> <div class="step"></div> <div class="step"></div> <div class="step"></div> </div> <div class="timeline-graphic"> <div class="step"></div> <div class="step"></div> <div class="step"></div> </div>
You can check if the current step
is the last in the parent by using
$(this).is(":last-child")
Note: it does need to be the last element, not just the last step
(without elements after). Nested each
is the cleanest solution (IMO) - see other answer.
There's an experimental :nth-last-child(1 of.step)
but that only works in Safari (so not recommended)
Updated snippet (without making any other changes, so this is unlikely to be the optimal/final solution)
var i = 0; $(".timeline-graphic.step").each(function(index, value) { var numItems = $(this).parent().length; $(this).css('left', i + 'px'); i = i + 20; if ($(this).is(":last-child")) i = 0; });
.timeline-graphic { height: 4px; background-color: #000; border-radius: 0.25rem; margin: 0 auto 80px auto; width: 100%; position: relative; }.step { position: absolute; top: -3px; width: 11px; height: 11px; background-color: red; border-radius: 50%; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div class="timeline-graphic"> <div class="step"></div> <div class="step"></div> <div class="step"></div> </div> <div class="timeline-graphic"> <div class="step"></div> <div class="step"></div> <div class="step"></div> <div class="step"></div> <div class="step"></div> <div class="step"></div> </div>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.