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 >
<div ></div>
<div ></div>
<div ></div>
</div>
<div >
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></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 >
<div ></div>
<div ></div>
<div ></div>
</div>
<div >
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
</div>
CodePudding user response:
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 >
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
</div>
<div >
<div ></div>
<div ></div>
<div ></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, e.g.
: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 >
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
</div>
<div >
<div ></div>
<div ></div>
<div ></div>
</div>
CodePudding user response:
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 >
<div ></div>
<div ></div>
<div ></div>
</div>
<div >
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
</div>