jQuery .click function - prevent it from being called again until function completes - javascript

I've written my first bit of proper jQuery for an image slideshow, that allows users to scroll up and down through some images:
$(window).load(function(){
$('.scrollUp').click(function(){
$('.cardWrapper:visible:first').prevAll(':hidden:first').slideDown(function(){
$('.cardWrapper:visible:last').slideUp();
});
return false;
});
$('.scrollDown').click(function(){
if($('.cardWrapper:last').is(':hidden')){
$('.cardWrapper:visible:last').nextAll(':hidden:first').slideDown();
$('.cardWrapper:visible:first').slideUp();
}
else{
$('.cardWrapper:last').after('<div class="cardWrapper"></div>');
$('.cardWrapper:last').load('/followedTestSingle/?sequence={{gr.sequence_token}}', function(){
$('.cardWrapper:visible:first').slideUp();
});
}
return false;
});
});
The problem I have is that if you click very fast on the .scrollDown element link - it loses all the content as it hasn't had the time to add the extra ( i think) - and thus it starts to fail.
Is there a way to make jQuery not accept any new click on an element until its run all of this function?

Maybe something like
var scrollDownClickActive = false;
$('.scrollDown').click(function(){
if (scrollDownClickActive) return false;
scrollDownClickActive = true;
if($('.cardWrapper:last').is(':hidden')){
$('.cardWrapper:visible:last').nextAll(':hidden:first').slideDown();
$('.cardWrapper:visible:first').slideUp(200, function(){ scrollDownClickActive = false; } );
}
else
{
$('.cardWrapper:last').after('<div class="cardWrapper"></div>');
$('.cardWrapper:last').load('/followedTestSingle/?sequence={{gr.sequence_token}}', function(){
$('.cardWrapper:visible:first').slideUp(200, function(){ scrollDownClickActive = false; } );
});
}
return false;
});
Using a flag to determine if the function is active or not.

The use of binding and unbinding removes the use of flag variables =)
function scroller(obj){
$(obj).unbind('click');
if($('.cardWrapper:last').is(':hidden')){
$('.cardWrapper:visible:last').nextAll(':hidden:first').slideDown();
$('.cardWrapper:visible:first').slideUp();
scrollDownClickActive = false;
}
else
{
$('.cardWrapper:last').after('<div class="cardWrapper"></div>');
$('.cardWrapper:last').load('/followedTestSingle/?sequence={{gr.sequence_token}}', function(){
$('.cardWrapper:visible:first').slideUp();
scrollDownClickActive = false;
});
}
$(obj).click(function(){scroller(this);});
}
$('.scrollDown').click(function(){
scroller(this);
});
Hope this helps!

If it's clicking an button element, just have your function disable it and re-enable it in the completion callback function.
Otherwise just write your function to check for a variable value which prevents it from running. If the variable isn't set, have it set a the value (something like var busy = true;) in the handler and set it back to false in the completion callback.

You can use a flag to indicate that it is scrolling (as suggested by MiffTheFox), but you'll have to unset the flag in the slide callback because the slide happens asynchronously:
$(function(){
var scrolling = false;
function startScrolling() {
if(scrolling) return false;
return scrolling = true;
}
function scrollComplete() {
scrolling = false;
}
$('.scrollUp').click(function() {
if(startScrolling()) return false;
$('.cardWrapper:visible:first')
.prevAll(':hidden:first').slideDown(function() {
$('.cardWrapper:visible:last').slideUp(scrollComplete);
});
return false;
});
$('.scrollDown').click(function() {
if(startScrolling()) return false;
if($('.cardWrapper:last').is(':hidden')) {
$('.cardWrapper:visible:last').nextAll(':hidden:first').slideDown();
$('.cardWrapper:visible:first').slideUp(scrollComplete);
} else {
$('.cardWrapper:last').after('<div class="cardWrapper"></div>');
$('.cardWrapper:last').load('/followedTestSingle/?sequence={{gr.sequence_token}}', function() {
$('.cardWrapper:visible:first').slideUp(scrollComplete);
});
}
return false;
});
});
Disclaimer: I haven't checked your code to see how valid it is, I've just added the flag and the callbacks for you.

Related

custom when statement not firing functions

I am trying to make a when statement but it is not working as planned. Basically its a function to call another function when try. First before I explain further here is the syntax
when(function() {
//code here
});
Now basically... Think this way.. We have a progressbar.. We also have a custom event such as...
var pBarEvent = document.createEvent('Event');
pBarEvent.initEvent('pbardone', true, true);
document.addEventListener('pbardone', function() {
//code here
});
//if progress bar reaches 100 dispatchEvent
if (document.querySelector(".progress-bar").style.width === 100 + "%")
{
document.dispatchEvent(pBarEvent);
}
Now that piece of code is an example. If the document loads and its for instance at 50% it wont trigger until you add another event such as keydown or click. I dont want to do that I want to do.... "when" progress bar width equals 100% trigger it. Thats basically what needs to happen. So here is the code for the when statement so far (keep in mind its not the best looking one. As I dont normally do this but I wanted to keep this dynamic and who knows someone who later wants to do this can look at this question)
when function
function when(func)
{
var nowActive = false;
if (!typeof func === 'undefined')
{
func = new Function();
}
if (func)
{
nowActive = true;
clearInterval(whenStatementTimer);
}
else
{
nowActive = false;
var whenStatementTimer = setInterval(function() {
switch(func)
{
case true:
{
nowActive = true;
when();
break;
}
case false:
{
nowActive = false;
when();
break;
}
}
}, 1000);
}
if (nowActive === true)
{
func();
}
}
Now this does not work when I go to try something like....
when(function() {
SmartLeadJS.SmartLeadEvents.customEvents.progressBarFull(function() {
alert("100%");
SmartLeadJS.SmartLeadAds.LeadView.ChromeExtension.General.DynamicStyles.$.style("body", "background", "black");
});
});
It does not trigger. I need help possibly getting this when statement to work. What am I doing wrong? What can I do to fix it? No errors get thrown but it never fires.
edit based on answer
Function tried
function when(currentValue)
{
try
{
var o = {};
o.currentValue = currentValue;
o.do = function(func)
{
if (!typeof func === 'undefined')
{
func = new Function();
}
if (this.currentValue)
{
func();
}
else
{
setTimeout(this.do(func), 100);
}
};
return o;
}
catch(e)
{
console.log(e);
}
}
used as
when(true).do(function() {
SmartLeadJS.SmartLeadEvents.customEvents.progressBarFull(function() {
alert("This divs going through changes!!");
SmartLeadJS.SmartLeadAds.LeadView.ChromeExtension.General.DynamicStyles.$.style(".div", "background", "black");
});
});
This does not work. It never fires. But if I use a onclick listener as such it fires
document.addEventListener("click", function() {
SmartLeadJS.SmartLeadEvents.customEvents.progressBarFull(function() {
alert("This divs going through changes!!");
SmartLeadJS.SmartLeadAds.LeadView.ChromeExtension.General.DynamicStyles.$.style(".div", "background", "black");
});
}, false);
function when(statement){
o={};
o.statement=statement;
o.do=function(func){
awhen(this.statement,func);
};
return o;
}
function awhen(statement,func){
if(eval(statement)){
func();
}else{
window.setTimeout(function(){awhen(statement,func);},100);
}
}
Use:
when("true").do(function(){});
It works now :) . Its important to put the condition in ""!

Disable JS Interaction Temporarily?

I want the following function to operate in a way that prevents users from spamming the mouseenter, mouseleave function, so that they can only operate the mouseenter/leave function once the fade action is complete. How would I do that?
$("#bocks").mouseenter(function(){
$("#bocks2").fadeOut(); });
$("#bocks").mouseleave(function(){
$("#bocks2").fadeIn();
});
http://jsfiddle.net/x2qNZ/
Try this:
var blocked = false;
function unblock() {
blocked = false;
}
$("#bocks").mouseenter(function(){
if (blocked) return;
blocked = true;
$("#bocks2").fadeOut(unblock);
});
$("#bocks").mouseleave(function(){
if (blocked) return;
blocked = true;
$("#bocks2").fadeIn(unblock);
});
You could also remove the event listeners and place it again in the unblock() function.
FadeIn/Fade out have completion callbacks.
http://jsfiddle.net/x2qNZ/3/
I have updated the Fiddle to disable fadeIn if we are actively fadingOut.
var isFiring = false;
$("#bocks").mouseenter(function(){
isFiring = true;
$("#bocks2").fadeOut(1000, function(){
isFiring = false;
});
});
$("#bocks").mouseleave(function(){
if(!isFiring){
$("#bocks2").fadeIn();
} else {
console.log('fire ignored');
}
});
Look at the updated fiddle
var mouseenterbusy = false;
var mouseleavebusy = false;
$("#bocks").mouseenter(function(){
if (mouseenterbusy == true) {
return;
}
mouseenterbusy = true;
$("#bocks2").fadeOut(function (){
mouseenterbusy = false;
});
});
$("#bocks").mouseleave(function(){
if (mouseleavebusy == true) {
return;
}
mouseleavebusy = true;
$("#bocks2").fadeIn(function (){
mouseleavebusy = false;
});
});
http://jsfiddle.net/x2qNZ/5/

Stop bind "blur" if click on a link

My bind function:
$searchInput.bind('blur', function() {
$searchResults.remove();
}
But this shouldn't happen if I click on a link inside of $searchResults. Now $searchResults is removed before I can click on a link.
How should I do that?
You may simply set a flag on mouse over $searchResults:
var isOver = false;
$searchInput.bind("blur", function(e) {
if (!isOver) {
$searchResults.remove();
}
});
$searchResults.hover(function() {
isOver = true;
}, function() {
isOver = false;
});
DEMO: http://jsfiddle.net/sUA4D/
You can do the same via element data, e.g. setting $searchResults.data("isOver", true).
One option that comes to mind is to delay the execution of the $.remove() call, like this:
$searchInput.bind('blur', function() {
setTimeout(function() {
$searchResults.remove();
}, 100);
}
$searchInput.find('a').on('click', function() {
$searchResults.remove();
});

Repetitive javascript call. can not disable

I use a JavaScript function to change the page when a function is clicked. An ajax call is made inside the function.
As the browser is slow. If I click more than one time on the button before the page changes (AJax div load. Page actually not changed), an ajax call is made for each click.
I used the following method to prevent. But even it is called many times. How can I prevent it?
var isClicked = function() {}
isClicked.init = function() {
this.clicked = false;
}
function myAjaxFunction {
//some statements
if(isClicked.clicked == 'undefined')
isClicked.clicked = false;
if(isClicked.clicked)
return false;
isClicked.clicked = true;
// my ajax call here
isClicked.clicked = false;
//some statements
}
var isClicked = false;
function AjaxFunction(){
if(isClicked){
return false;
}
// Set your variable.
isClicked = true;
// Do yourAjaxCall and use isClicked = false in the callback of that function.
}

Stopping .click() listener until fadeIn() is finished in jQuery

$('#div1_button').click(function() {
$('#div0').fadeOut(function(){
$('#div1').fadeIn();
});
});
When a user clicks div1_button the previously selected div0 fades out and div1 fades in. If the user goes click crazy and clicks div2 before div1 is finished fading in then div2 begins to fade in and eventually div1 fades out, but they stack on top of each other until div1 is finished fading in then fades out. How can I stop the .click() event until the clicked div is finished fading in.
Something like
var div1_bclick_inprogress = false;
$('#div1_button').click(function() {
if (!div1_bclick_inprogress) {
div1_bclick_inprogress = true;
$('#div0').fadeOut(function(){
$('#div1').fadeIn(function(){
div1_bclick_inprogress = false;
});
});
}
});
but you may have to experiment a bit with the details
USE :animated ..
http://api.jquery.com/animated-selector/
Here: an example
$("#div1_button").click(function() {
if (!$(this).parent().children().is(':animated')) {
$('#div0').fadeOut(function(){
$('#div1').fadeIn();
});
}
return false;
});
You can stop animations by using the jQuery .stop() function.
http://api.jquery.com/stop/
$('#div1_button').click(function() {
$('#div0').stop(true, true).fadeOut(function(){
$('#div1').stop(true, true).fadeIn();
});
});
While this is not exactly what you requested, it's definitely what I would've done.
don't you think that is better to stop the fadeIn/fadeOut and change the direction as the user requested?
in this case:
$('#div1_button').click(function() {
var state = $(this).data("state");
$(this).data(state, !state);
var d0 = $("#div0").stop(),
d1 = $("#div1").stop();
if (state) {
d0.fadeOut(function() {
d1.fadeIn();
});
} else {
d0.fadeIn(function() {
d1.fadeOut();
});
}
});
or something like this
div1_click_handler = function()
{
$('#div1_button').unbind('click', div1_click_handler);
$('#div0').fadeOut('slow', function()
{
$('#div1').fadeIn('slow', function()
{
$('#div1_button').click(div1_click_handler);
});
});
});
$('#div1_button').click(div1_click_handler);
You could create an external boolean value that each click value checks before fading. i.e.
var noFading = true;
$('#div1_button').click(function() {
if (noFading) {
noFading = false;
$('#div0').fadeOut(function(){
$('#div1').fadeIn(function() { noFading = true; });
});
}
});
Use jQuery.data to store a flag. Set the flag after the first click, and ignore clicks until the flag is unset by the fade finishing:
$('#div1_button').click(function() {
if ($('#div1').data('disableClick') === true) return false;
$('#div1').data('disableClick', true);
$('#div0').fadeOut(function(){
$('#div1').fadeIn(function() {
$('#div1').data('disableClick', false);
});
});
});

Categories