0

I have a script that enhances a button so the page can return to top and then open a sidebar. It contains script that allows a button 'reset' as it is an on click script. The reset part only works once after a page refresh and will not work after that. The bottom part 'toggleClick(true);' is the part that only works once. How can I make it so the reset part works consistently?

jQuery(document).ready(function($) {
  function toggleClick(on) {
    if (on) {
      $('.button').on('click', function() {
        setTimeout(function() {
          $('.sidebaropen')[0].click()
        }, 210);
        $("html, body").animate({
          scrollTop: 0
        }, "fast");
        toggleClick(false);
        console.log('clicked');
      });

    } else {
      $('.button').off('click');
    }

  }
  toggleClick(true);

  $('.button').on('click', function() {
    console.log('Reset done');
    setTimeout(function() {
      toggleClick(true);
    }, 210);
  });
});
VLAZ
  • 26,331
  • 9
  • 49
  • 67

3 Answers3

0

You're calling toggleClick(false) which removes the click handler after the button is clicked. It is equivalent to using $('.button').one(...).

Why remove the click handler at all? You could just hide the button when the page is already scrolled to the top. Here's some code that I've used in the past. It's not pretty, but it works:

// scrollStopped function modified from accepted answer at 
// https://stackoverflow.com/questions/14035083/jquery-bind-event-on-scroll-stop/14035162#14035162
$.fn.scrollStopped = function (callback) {
  var $this = $(this),
    self = this;
  $this.scroll(function () {
    if ($this.data('scrollTimeout')) {
      clearTimeout($this.data('scrollTimeout'));
    }
    $this.data('scrollTimeout', setTimeout(callback, 250, self));
  });
};

// If the menu is out of view (in my case, at 215px), show the button
// fadeIn/fadeOut not necessary; you could just use show/hide
$(window).scrollStopped(function () {
  if ($(this).scrollTop() > 215) {
    $('.button').fadeIn('fast');
  } else {
    $('.button').fadeOut('fast');
  }
});

// button click scrolls back to the top of the page
$('.button').click(function () {
  $('html, body').animate({
    scrollTop: 0
  });
  // You can add your .sidebaropen click here
});
J. Titus
  • 9,535
  • 1
  • 32
  • 45
  • There a few specific circumstances that mean I have to remove the handler. I'm really just looking for a solution where the 'reset' will always work without the need for a page refresh. Thanks for your help – user17098947 Oct 25 '21 at 11:42
0

JQuery.off removes all event listeners for a given element. Therefore, your second event for Reset done is getting removed as well from the first event callback. Honestly, the best way to fix this is to just use vanilla JavaScript as you cannot remove a specific event instance with JQuery:

const $btn = document.querySelector(".button");

const handleClick = () => {
  $("html, body").animate({
    scrollTop: 0
  }, "fast");
  toggleClick(false);
};

function toggleClick(state) {
  if (state) {  
    $btn.addEventListener('click', handleClick);
  } else {
    $btn.removeEventListener('click', handleClick);
  }
}

toggleClick(true);

$('.button').on('click', function() {
  setTimeout(function() {
    toggleClick(true);
  }, 210);
});
div {
  min-height: 200vh;
}

.button {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>So contentful</div>
<button class="button">Go Up</button>
<aside class="sidebar">Awesome sidebar</aside>
sno2
  • 3,274
  • 11
  • 37
  • Good solution, but I just wanted to note that your claim of "you cannot remove a specific event instance with JQuery" is incorrect. Passing the handler function like you're doing in vanilla JS has the same effect: https://api.jquery.com/off/ – J. Titus Oct 23 '21 at 15:31
0

Easy way to do this. Please read the comments for more clarification.

$(document).ready(function(){
   $('.button').on('click', function() {
       var isClicked = $(this).attr("isClicked"); // get the attr value from the button it not found in first time
if(!isClicked){ // check if isClicked not found
        setTimeout(function() {
          $('.sidebaropen')[0].click()
        }, 210);
        $("html, body").animate({
          scrollTop: 0
        }, "fast");
$(this).attr("isClicked",1); // when you cliked the button this will set the isClcked attribute to your button
       }
 });
});

Thanks

  • Thanks Shubham. This has the same effect as my own code. The scrolltop and sidebar open is only happening once before the page needs a refresh. – user17098947 Oct 25 '21 at 11:26