Home > front end >  How to detect end of elements in div with jQuery each() on multiple div
How to detect end of elements in div with jQuery each() on multiple div

Time:01-20

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>

  • Related