How to get the highest of the elements in each of multiple wrappers with JavaScript?

76 views Asked by At

I already have half of the solution, but my function only marks a single element in the entire DOM, regardless of the fact that there are several wrapper elements, whose child elements should be queried for height and the highest one of each wrapper marked. I do not need the value.

"use strict";

const slides = document.querySelectorAll(".slider_inner > .block");

let maxHeight = 0;
let maxHeightElement = null;
slides.forEach(el => {
  let elementHeight = el.offsetHeight;
  if (elementHeight > maxHeight) {
    maxHeight = elementHeight;
    maxHeightElement = el;
  }
});

if (maxHeightElement !== null) {
  maxHeightElement.classList.add("highest");
  maxHeightElement.parentNode.classList.add("highest_defined");
}
.highest{
  background-color: red;
}

.slider_inner{
  margin-bottom: 20px;
}
<div class="slider_inner">
  <div class="block">Slide 1</div>
  <div class="block">Slide 2</div>
  <div class="block">Slide 3<br>Slide 3</div>
  <div class="block">Slide 4</div>
  <div class="block">Slide 5</div>
</div>


<div class="slider_inner">
  <div class="block">Slide 1</div>
  <div class="block">Slide 2<br>Slide 2</div>
  <div class="block">Slide 3</div>
  <div class="block">Slide 4<br>Slide 4<br>Slide 4</div>
  <div class="block">Slide 5</div>
</div>

2

There are 2 answers

1
mplungjan On BEST ANSWER

You need to move your class assignment into the loop.

Alternatively you can use Math.max when you run over the wrappers

This is not marking blocks with same height, you can loop over the heights if you want to mark more than one.

const sliders = document.querySelectorAll(".slider_inner");
sliders.forEach(slider => {
  const blocks = slider.querySelectorAll(".block");
  const heights = [...blocks].map(block => block.offsetHeight);
  // Find the maximum height
  const maxHeight = Math.max(...heights);

  // Find the index of the block with the maximum height
  const tallestBlockIndex = heights.indexOf(maxHeight);

  if (blocks[tallestBlockIndex]) {
    blocks[tallestBlockIndex].classList.add("highest");
    slider.classList.add("highest_defined");
  }
});
.highest {
  background-color: red;
}

.slider_inner {
  margin-bottom: 20px;
}

.highest_defined {
  border: 1px solid black
}
<div class="slider_inner">
  <div class="block">Slide 1</div>
  <div class="block">Slide 2</div>
  <div class="block">Slide 3<br>Slide 3</div>
  <div class="block">Slide 4</div>
  <div class="block">Slide 5</div>
</div>


<div class="slider_inner">
  <div class="block">Slide 1</div>
  <div class="block">Slide 2<br>Slide 2</div>
  <div class="block">Slide 3</div>
  <div class="block">Slide 4<br>Slide 4<br>Slide 4</div>
  <div class="block">Slide 5</div>
</div>

4
3limin4t0r On

Instead of looping through all the .slide_inner > .block elements. You want to do two loops. One through all .slide_inner elements. Then for each .slide_inner element, you want to loop through the :scope > .block elements to determine which is the highest within this .slider_inner.

"use strict";

const containers = document.querySelectorAll(".slider_inner");
// loop through the .slider_inner containers
for (const container of containers) {
  // for each container, collect the .block elements that are a direct child
  const slides = container.querySelectorAll(":scope > .block");
  // exit the current iteration early if there are no .block children
  if (!slides.length) continue;
  // find the highest slide
  const highestSlide = maxBy(slides, slide => slide.offsetHeight);
  // add the "highest" class to the highest slide
  highestSlide.classList.add("highest");
}

// Abstracted away getting the item with the highest value from an iterable
// collection.
function maxBy(iterable, valueFn) {
  return Array.from(iterable, (item) => ({ item, value: valueFn(item) }))
    .reduce((max, current) => current.value > max.value ? current : max)
    .item;
}
.highest{
  background-color: red;
}

.slider_inner{
  margin-bottom: 20px;
}
<div class="slider_inner">
  <div class="block">Slide 1</div>
  <div class="block">Slide 2</div>
  <div class="block">Slide 3<br>Slide 3</div>
  <div class="block">Slide 4</div>
  <div class="block">Slide 5</div>
</div>


<div class="slider_inner">
  <div class="block">Slide 1</div>
  <div class="block">Slide 2<br>Slide 2</div>
  <div class="block">Slide 3</div>
  <div class="block">Slide 4<br>Slide 4<br>Slide 4</div>
  <div class="block">Slide 5</div>
</div>