1

By clicking a 'next' or 'prev' button, I am trying to add a class ('.active') to the next or previous image. Why does my code currently only works one time --it adds the class to the next image-- and then stops working?

Link:

http://jordy.studio/paintings_new

$('#thumbnails').each(function() {
  $('#thumbnails').find('img').first().addClass('active');
});

$("#next").click(function() {
  $('#thumbnails').find('img').hasClass('active').removeClass('active').first().next('img').addClass('active');
});

$("#prev").click(function() {
  $('#thumbnails').find('img').removeClass('active').prev('img').first().addClass('active');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="thumbnails">
  <img class="active" src="img_01.jpg">
  <img class="      " src="img_02.jpg">
  <img class="      " src="img_03.jpg">
  <img class="      " src="img_04.jpg">
</div>

<footer>
  <p id="prev">prev</p>
  <p id="next">next</p>
</footer>

Trying to use jQuery .siblings resulted in all next images being given the class '.active'.

Just spent a good night on trying to get this to work I hope someone can explain to me what I am doing wrong. Although enthusiast about jQuery I have not much experience. Everyday is a school day!

connexo
  • 53,704
  • 14
  • 91
  • 128
Jordy
  • 347
  • 2
  • 11

1 Answers1

2

The issue is mainly because hasClass() returns a boolean indicating if the element in the collection has the class you provide. It does not return a jQuery object, so you cannot chain other methods off it.

To fix this you can store a single object containing all img elements then filter() them to find the .active one.

Also note that calling each() on an id selector, as you do on #thumbnails, is redundant as there should only ever be one element with that id. If there are multiple change that to a class selector. In addition you should set the active class on the default element in HTML as doing it in JS will result in a FOUC.

With all that said, try this:

let $img = $('#thumbnails img');

$("#next").click(function() {
  let $target = $img.filter('.active').removeClass('active').next();
  if ($target.length == 0)
    $target = $img.first();
  $target.addClass('active');
});

$("#prev").click(function() {
  let $target = $img.filter('.active').removeClass('active').prev();
  if ($target.length == 0)
    $target = $img.last();
  $target.addClass('active');
});
img {
  display: block;
  width: 25px;
  height: 25px;
  border: 1px solid #C00;
}

img.active {
  background-color: #C00;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="thumbnails">
  <img src="img_01.jpg" class="active">
  <img src="img_02.jpg">
  <img src="img_03.jpg">
  <img src="img_04.jpg">
</div>

<footer>
  <p id="prev">prev</p>
  <p id="next">next</p>
</footer>
Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339
  • Thank you. I didn't realise hitting 'prev' at the very start isn't doing much and a solution would be 'looping' through the images (jump to first img after last img -- and the other way around). Do I look into adding the jQuery length method? How would you approach this? – Jordy May 04 '20 at 15:08
  • Yep, in that case you can use `length` to check if the next/prev element exists. If it doesn't go back to the start/end – Rory McCrossan May 04 '20 at 15:13
  • I've updated the answer to show you exactly how to do it. – Rory McCrossan May 04 '20 at 15:14
  • Works perfectly well. One last jQuestion, why did you add 'let' at the very start of the code? I've never seen this before. I usually see 'var'. Many thanks! – Jordy May 04 '20 at 15:19
  • 1
    Nevermind! https://stackoverflow.com/questions/762011/whats-the-difference-between-using-let-and-var – Jordy May 04 '20 at 15:19