univers_
univers_

Reputation: 463

Event inside click function firing outside click

I'm using the hash to detect the current slide in a slideshow but I'd like to only do so when the slideshow is advanced using the previous or next buttons. But the event "cycle-after" which detects a transition in the slideshow, is firing even when the previous or next buttons are not clicked.

How do I make that event only run during the click function?

JSFiddle here: https://jsfiddle.net/yd8L3enj/4/

$(document).ready(function() {
  var clicked = false;

  $('.controls').on('click', function() {
    $('.cycle-slideshow').on('cycle-after', function(event, optionHash) {
      var hash = window.location.hash;
      $('.clicked').removeClass('clicked')
      if (window.location.hash === hash) {
        $(hash).addClass('clicked')
      } else {
        $(hash).removeClass('clicked')
      }
    });
  });

  $('nav a').on('click', function() {
    clicked = !clicked;
    $('.clicked').removeClass('clicked');
    $(this).addClass('clicked');
    $('.content').addClass('visible');
  });

  $("nav a").mouseenter(function() {
    var href = $(this).attr('href');
    window.location.hash = href
    $('.content').addClass('visible');
  }).mouseleave(function() {
    var current = $('.clicked').attr('href');
    window.location.hash = current
    if ($(".clicked")[0]) {
      // Do something if class exists
    } else {
      $('.content').removeClass('visible');
    }
  });




  $('.close').on('click', function() {
    $('.content').removeClass('visible');
    window.location.hash = ""
    clicked = !clicked;
  });


});
body {
  font-size: 150%;
}

img {
  width: 50vw;
  height: auto;
}

.clicked {
  color: green;
}

.content {
  display: none;
}

.visible {
  display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.cycle2/2.1.6/jquery.cycle2.min.js"></script>
<nav>
  <a href="#1" id="1">1</a>
  <a href="#2" id="2">2</a>
  <a href="#3" id="3">3</a>
</nav>
<div class="content">
  <div class="cycle-slideshow" data-cycle-slides="> div" data-cycle-timeout="0" data-cycle-prev=".prev" data-cycle-next=".next" data-cycle-speed="1" data-cycle-fx="fadeOut">
    <div data-cycle-hash="1">
      <img src="https://placeimg.com/640/480/animals">
    </div>
    <div data-cycle-hash="1">
      <img src="https://placeimg.com/640/480/animals/2">
    </div>
    <div data-cycle-hash="2">
      <img src="https://placeimg.com/640/480/arch">
    </div>
    <div data-cycle-hash="2">
      <img src="https://placeimg.com/640/480/arch/2">
    </div>
    <div data-cycle-hash="3">
      <img src="https://placeimg.com/640/480/nature">
    </div>
    <div data-cycle-hash="3">
      <img src="https://placeimg.com/640/480/nature/2">
    </div>
  </div>
  <div class="controls">
    <div class="prev">Prev</div>
    <div class="next">Next</div>
    <div class="close">Close</div>
  </div>
</div>

Upvotes: 0

Views: 44

Answers (1)

Joeri Hendrickx
Joeri Hendrickx

Reputation: 17435

the $(selector).on(... syntax binds an event listener. Your code is adding an event listener to the 'cycle-after' event every time the click listener is executed. That means, as soon it was clicked once, all cycle-after events from then on will have that code executed. If you clicked multiple times, you will have bound multiple listeners, and even more of them will be running on every cycle-after event.

What you probably want to do is, for a click, only perform the code after the first next cycle-after event. To achieve this you could bind the listener, and at the end of the callback, unbind it again. Something like this:

  $('.controls').on('click', function() {
    $('.cycle-slideshow').on('cycle-after', afterCycle);

    function afterCycle(){
      ... your logic here ...
      $('.cycle-slideshow').off('cycle-after', afterCycle);
    }
  });

Keep in mind that this is still pretty fragile. If you click twice before the first cycle-after happens, the library might only fire cycle-after once and you will still have an unwanted listener bound. If this slide-library supports it, it would be best to simply bind once on 'cycle-after', and then add a check that only continues if the cycle was caused by a click.

Upvotes: 1

Related Questions