1

I have this small script who's role is to help with responsive grid layouts by adding the class last-row to the grid items placed on the last row:

function addLastRowClass() {
  $(".blocks_section").each(function() {
    var $grid_item = $(this).find(".news_box");
    var maxTop = $grid_item.removeClass("last-row").map(function() {
      var $item = $(this)
      return $item.position().top;
    }).get().reduce((acc, curr) => (curr > acc) ? curr : acc)

    $grid_item.filter(function() {
      var $item = $(this)
      return $item.position().top == maxTop;
    }).addClass("last-row");
  });
}

addLastRowClass();
$(window).resize(addLastRowClass);
.blocks_section {
  margin-top: 15px;
  display: flex;
  flex-wrap: wrap;
}

.blocks_section .news_box {
  display: flex;
  flex-direction: column;
  background: #fff;
  margin-bottom: 15px;
}

.blocks_section .news_box .content {
  border: 1px solid #d5d5d5;
  flex-grow: 1;
}

.blocks_section .news_box .title {
  padding: 8px 8px 0 8px;
}

.blocks_section .text {
  padding: 8px;
}

.blocks_section .title {
  font-size: 1.25rem;
  margin-bottom: 8px;
  text-transform: capitalize;
}

.blocks_section .text {
  margin-bottom: 8px;
  text-align: justify;
}

.blocks_section .thumbnail img {
  display: block;
  width: 100%;
  height: auto;
}

@media (max-width: 767px) {
  .container {
    max-width: 100%;
  }
}

@media (max-width: 575px) {
  .container {
    max-width: 100%;
    padding-left: 0;
    padding-right: 0;
  }
  .blocks_section .news_box {
    padding-left: 5px;
    padding-right: 5px;
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" rel="stylesheet" />

<h1 chass="h3">Lorem ipsum dolor</h1>
<div class="blocks_section">
  <div class="news_box col-xs-12 col-sm-6 col-md-4">
    <div class="content">
      <div class="thumbnail"><img src="https://i.stack.imgur.com/ZeOrf.jpg"></div>
      <h2 class="title">Lorem ipsum dolor</h2>
      <p class="text">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatem inventore eos in voluptas ab, aut pariatur, dolores atque neque consequuntur.</p>
    </div>
  </div>
  <div class="news_box col-xs-12 col-sm-6 col-md-4">
    <div class="content">
      <div class="thumbnail"><img src="https://i.stack.imgur.com/TICOa.jpg"></div>
      <h2 class="title">Lorem ipsum dolor</h2>
      <p class="text">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatem inventore eos in voluptas ab, aut pariatur, dolores atque neque consequuntur.</p>
    </div>
  </div>
  <div class="news_box col-xs-12 col-sm-6 col-md-4">
    <div class="content">
      <div class="thumbnail"><img src="https://i.stack.imgur.com/ZeOrf.jpg"></div>
      <h2 class="title">Lorem ipsum dolor</h2>
      <p class="text">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatem inventore eos in voluptas ab, aut pariatur, dolores atque neque consequuntur.</p>
    </div>
  </div>
  <div class="news_box col-xs-12 col-sm-6 col-md-4">
    <div class="content">
      <div class="thumbnail"><img src="https://i.stack.imgur.com/TICOa.jpg"></div>
      <h2 class="title">Lorem ipsum dolor</h2>
      <p class="text">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatem inventore eos in voluptas ab, aut pariatur, dolores atque neque consequuntur.</p>
    </div>
  </div>
</div>

<h1 chass="h3">Praesentium, provident</h1>
<div class="blocks_section">
  <div class="news_box col-xs-12 col-sm-6 col-md-4">
    <div class="content">
      <div class="thumbnail"><img src="https://i.stack.imgur.com/ZeOrf.jpg"></div>
      <h2 class="title">Lorem ipsum dolor</h2>
      <p class="text">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatem inventore eos in voluptas ab, aut pariatur, dolores atque neque consequuntur.</p>
    </div>
  </div>
  <div class="news_box col-xs-12 col-sm-6 col-md-4">
    <div class="content">
      <div class="thumbnail"><img src="https://i.stack.imgur.com/TICOa.jpg"></div>
      <h2 class="title">Lorem ipsum dolor</h2>
      <p class="text">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatem inventore eos in voluptas ab, aut pariatur, dolores atque neque consequuntur.</p>
    </div>
  </div>
  <div class="news_box col-xs-12 col-sm-6 col-md-4">
    <div class="content">
      <div class="thumbnail"><img src="https://i.stack.imgur.com/ZeOrf.jpg"></div>
      <h2 class="title">Lorem ipsum dolor</h2>
      <p class="text">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatem inventore eos in voluptas ab, aut pariatur, dolores atque neque consequuntur.</p>
    </div>
  </div>
  <div class="news_box col-xs-12 col-sm-6 col-md-4">
    <div class="content">
      <div class="thumbnail"><img src="https://i.stack.imgur.com/TICOa.jpg"></div>
      <h2 class="title">Lorem ipsum dolor</h2>
      <p class="text">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatem inventore eos in voluptas ab, aut pariatur, dolores atque neque consequuntur.</p>
    </div>
  </div>
</div>

It has a simple and clear logic and it works but, on complex pages with multiple responsive grids, the console through the error: Reduce of empty array with no initial value, leaving the second (third, etc) grid without this feature.

Questions:

  • What is the cause of the error?
  • What is the solution to the problem?
Razvan Zamfir
  • 4,209
  • 6
  • 38
  • 252

1 Answers1

1

To understand what's happening, you have to wonder what is reduce doing :

The first time the callback is called, accumulator and currentValue can be one of two values. If initialValue is provided in the call to reduce(), then accumulator will be equal to initialValue, and currentValue will be equal to the first value in the array. If no initialValue is provided, then accumulator will be equal to the first value in the array, and currentValue will be equal to the second.

If you provide an empty array with no itinial value, say :

[].reduce(() => {})

Then it does not make sense anymore, since you cannot either access the first element of the array or use an initial value. All you have to do is provide an initial value :

myArray.reduce(() => {}, [])

Since your reduce function is using numbers and and you want to find the maximum of them, you can use -Infinity as an initial value :

myArray.reduce((acc, curr) => Math.max(acc, curr), -Infinity)

So, for your use case :

function addLastRowClass() {
  $(".blocks_section").each(function() {
      var $grid_item = $(this).find(".news_box");
      var maxTop = $grid_item.removeClass("last-row").map(function() {
          var $item = $(this)
          return $item.position().top;
      }).get().reduce((acc, curr) => (curr > acc) ? curr : acc, -Infinity) //<--- Initial value provided here

      $grid_item.filter(function() {
          var $item = $(this)
          return $item.position().top == maxTop;
      }).addClass("last-row");
  });
}

On a side note, if you can use array destructuring, you could simply do the following :

function addLastRowClass() {
  $(".blocks_section").each(function() {
      var $grid_item = $(this).find(".news_box");
      var topPositions = $grid_item
          .removeClass("last-row")
          .map((i, el) => $(el).position().top)
          .get();
      var max_top = Math.max(...topPositions); // <-- Here
      $grid_item
          .filter((i, el) => $(el).position().top == maxTop)
          .addClass("last-row");
  });
}

Edit

Just noticed what you were trying to do there. Your problem will arise only when there is no items in the grid, but in this case you don't have anything to do, so another way to do it is to check the items length before processing :

function addLastRowClass() {
  $(".blocks_section").each(function() {
      var $grid_item = $(this).find(".news_box");
      if($grid_item.length) {
          var maxTop = $grid_item.removeClass("last-row").map(function() {
              var $item = $(this)
              return $item.position().top;
          }).get().reduce((acc, curr) => (curr > acc) ? curr : acc)

          $grid_item.filter(function() {
              var $item = $(this)
              return $item.position().top == maxTop;
          }).addClass("last-row");
      }
  });
}
Logar
  • 1,248
  • 9
  • 17
  • Great answer, the bug is fixed. Thanks, Logar! (Is Logar your real name or just a username?) – Razvan Zamfir Aug 29 '18 at 14:35
  • Glad I helped ;) It's just a username, I've heard it means something in some east european languages, but it's a pure coincidence :) – Logar Aug 29 '18 at 14:39
  • Well, what's your real name? – Razvan Zamfir Aug 29 '18 at 14:41
  • @RazvanZamfir my real name is Simon, why ? – Logar Aug 29 '18 at 15:08
  • I need/want to know who's helping me. – Razvan Zamfir Aug 29 '18 at 15:23
  • There is a 100 reputation BOUNTY for **[this question](https://stackoverflow.com/questions/51894403/prevent-event-overlap-in-custom-jquery-image-carousel)**. Interested? :) – Razvan Zamfir Aug 30 '18 at 09:26
  • @RazvanZamfir why not, seems interesting, will take a look at it when I've got a bit of time ;) – Logar Aug 30 '18 at 12:50
  • I have posted the topic *[Change the fixed navbar's classes depending on the background of the page section it hovers](https://stackoverflow.com/questions/52118919/change-the-fixed-navbars-classes-depending-on-the-background-of-the-page-sectio)*. Please have a look at it. Thanks! – Razvan Zamfir Sep 02 '18 at 07:02