I'm using this Codrops Blueprint to create a quotes rotator. I modified the rotator to have a next button, powered by the code below:
_startRotator: function() {
if (this.support) {
this._startProgress();
}
var timeout = setTimeout($.proxy(function() {
if (this.support) {
this._resetProgress();
}
this._next();
this._startRotator();
}, this), this.options.interval);
$(".testimonial-next").click($.proxy(function() {
clearTimeout(timeout);
if (this.support) {
this._resetProgress();
}
this._next();
this._startRotator();
}, this));
},
I added the .click function below the setTimeout function, and added the var to the setTimeout function.
When .testimonial-next is clicked, the rotator's timer is reset and the code in the timer is instantly executed. As far as I can tell, the timer restarts itself, so I shouldn't have to add code to do this.
On the website where this is put to use (see the "Testimonials" section), however, there seems to be a problem. There should be five quotes, in the order of Kim, Lynn, Shannon, Jennifer, and Chris. If the timer runs without being interrupted, everything works as expected. If the Next button is clicked, certain quotes seem to be skipped. Other times, the quotes stop rotating or randomly rotate at a high speed.
What am I doing wrong?
Your button click handler is attached again and again to the button, making a click result in several executions of the same code.
To solve this you can best move that piece of code out of the _startRotator function and move it somewhere where it will only be executed once.
That way, when you click, there will be only one handler that gets executed.
Less nice, but also a solution, would be to keep the code where it is, but always first remove any existing click handler, before you attach it again:
$(".testimonial-next").off('click').on('click', $.proxy(function() {
// etc...
But this is really an ugly solution. Try to move the code.
Related
I have an input type="number" and am using the up/down arrows within the field to change the value of the input. I want to trigger a function after the final click/change of the input.
By final I mean after the input hasn't been changed for 1000ms (my assumption that the user has now stopped clicking).
I've set up a 1000ms setTimeout() that runs the function, but even though I'm calling clearTimeout() .on('change') of the input, the function runs 1000ms after the first change, rather than the last.
I've set up a simple JSFiddle to illustrate what I mean. The div with "Hello World!" in it should not appear until after the final click.
If you rapidly click the up arrow on the input (at least once every 999ms) then the div should never appear.
I have looked through a lot of other similar questions on here but they're almost all about the scope of the timer variable, which I don't think applies here.
What am I doing wrong?
onchange, is triggered when input loses its focus, try on input.. btw. jquery is not required here.
var timeOut;
document.getElementById("foo").addEventListener("input", function() {
clearTimeout(timeOut);
timeOut = setTimeout(function() {
document.getElementById("bar").style.display = "block";
}, 1000);
});
In my game, when you die a game over screen but for some reason when you click main menu, then level one again, and move to the left or right it double moves him? Every time you click start I made it so that it resets it again just in case maybe that is why? here is the function that i think might be causing the problome?
$('#yes').click(function() {
$("#levelOne").css('margin-top', '-1520px');
$("#player").css('border', 'solid 1px green')
$("#player").css('margin-left', '223px');
$('#levelComplete').hide();
$('#levelOne').animate({
'margin-top': '+=1520px'
}, speed);
handleCollisions()
$('#startLevel1').hide();
});
link: http://jsfiddle.net/8h7n2oca/20/
Any thing helps, thanks
When the game resets, sounds like an event is being re-bound to your player (resulting in 2 duplicate events bound to your player) Make sure to unbind all relevant events on gameover / be careful in rebinding.
Thanks for the fiddle, I took at a look at your code. When you start the game, you call the function levelOne(), inside this function the following code runs:
document.addEventListener('keydown', function (evt) { /* your logic */ }
This code is binding an event listener on the keydown event to the document. When you call levelOne() after the game ends, this code runs again. Now you have two listeners bound to the document. So when you go to move your player, the code is fired twice.
Abstracting your game set up logic to a separate function to be run once on page load as suggested by GameAlchemist sounds like a good approach to prevent duplicate bindings and optimize your code.
I have some animation in my code and I have faced a problem: When the user clicks the button more than once my animation will become faster and faster. To deal with this I have included the refresh page function (location.reload()) inside the function below.
Now I have a major problem: when I execute the button supposed the reload page function will be executed first then follow by day2 function then day1 function... the problem is now only the refresh page function is been executed.
How do I overcome this problem?
Javascript:
function day()
{
location.reload().then(day2).then(day1);
}
HTML:
<input type="button" id="buttonThree" value="Day" onclick="day()"/>
What you're doing doesn't work
Now I have a major problem: when I execute the button supposed the reload page function will be executed first then follow by day2 function then day1 function... the problem is now only the refresh page function is been executed.
Well, yeah. You refreshed the page. That involves leaving the page then re-entering it. Leaving the page means your JavaScript ends everything it's doing, and re-entering it means your JavaScript starts anew. JavaScript does not transcend page loads.
If you want your JavaScript to communicate with JavaScript on other pages, do so via other means: an #anchor in the URI, a query string in the URI, form data, sessionStorage, localStorage, or cookies - those are arranged in order of permanence and appropriateness, with cookies completely overdoing it, and #anchors and query strings being completely appropriate.
But that's completely unnecessary and inappropriate here. You shouldn't be doing what you're doing in the first place.
Let's address the actual problem of multiple button presses
I have some animation in my code and I have faced a problem: When the user clicks the button more than once my animation will become faster and faster.
Simply put, you shouldn't be doing what you're doing and this problem has a much simpler solution: disable the button, or set a boolean flag, in order to prevent the animation from running multiple times. Simply, don't allow the animation to run multiple times.
Option 1: Disabling the button
Disabling the button prevents it from sending onclick events, and signals to your user the button won't do anything for now. I recommend doing this if your button should not do anything longer whilst the animation is running, or whilst something else is happening.
The approach is to disable the button as soon as it's clicked. Later, once the tasks that button fired off (such as the animation) are finished, and it's OK to click the button again, you re-enable the button.
<input type="button" id="animateButton" value="Animate" onclick="animate()"/>
function animate() {
// 'this' refers to the button, when the button's click event
// calls this function
this.disabled = true;
startAnimation();
}
function startAnimation() {
// run the animation
// ...
// once the animation is completed, via whatever means you want
// (such as by jQuery's animate.complete callback),
// re-enable the button like this:
document.getElementById("animateButton").disabled = false;
// or address the button some other appropriate way.
}
Option 2: Boolean flag, leaving the button enabled but doing nothing
This approach involves using a boolean flag to ignore clicks when the animation is running, instead of disabling the button outright.
This lets the user click the button still. It's useful if you want the button enabled for whatever reason, such as if you want the button doing other things on click - just without starting the animation every time.
If it's not going to do anything except start the animation, however, you probably should use option 1 instead to disable it, signalling the button won't do anything for now.
If you want this button to do other things, I suggest you have it call a different function - for example, doStuff() - and have that function call the animate() function below.
<input type="button" id="animateButton" value="Animate" onclick="animate()"/>
var canAnimate = true;
function animate() {
if (!canAnimate) return; // do nothing if we're not allowed to animate yet
canAnimate = false;
startAnimation();
}
function startAnimation() {
// run the animation
// ...
// once the animation is completed, via whatever means you want
// (such as by jQuery's animate.complete callback),
// set the flag to say we can animate again, like this:
canAnimate = true;
}
OK I am lost here. I have read numerous postings here and else where on the topic of how to check for the state of a given element in particular whether it is visible or hidden and make the change of state trigger an event. But I cannot make any of the suggested solutions work.
Firstly, as every one seems to leap on this point first, the need to do this has arisen as I have one jQuery script which deals with displaying an svg icon in a clickable state. And another which already has functions to perform relevant actions when the form is made visible by clicking the icon and obviously I want to reuse these.
What I have tried:
Initially I tried have both the scripts acting on a single click event (this remains the ideal solution)....
Script 1:
$(".booked").on("click", function() {
$("#cancellation_Form_Wrapper").css("visibility","visible");
}).svg({loadURL: '../_public/_icons/booked.svg'});
Script 2:
$(".booked").on("click", function() {
// do stuff
});
This did not work so I tried to research sharing an event across two scripts but couldn't make any head way on this subject so I tried triggering another event for the second script to pick up....
Script 1:
$(".booked").on("click", function() {
$("#cancellation_Form_Wrapper").css("visibility","visible");
$("#cancellation_Form_Wrapper").trigger("change");
}).svg({loadURL: '../_public/_icons/booked.svg'});
Script 2
$("#cancellation_Form_Wrapper").on("change", function(event){
// do stuff
});
This did not work again I am unclear why this didn't have the desired effect.
Then I tried is(:visible) ....
Script 1
$(".booked").on("click", function() {
$("#cancellation_Form_Wrapper").css("visibility","visible");
}).svg({loadURL: '../_public/_icons/booked.svg'});
Script 2
$("#cancellation_Form_Wrapper").is(":visible", function(){
// do stuff
});
So I am a bit lost. The ideal would be to return to the first notion. I do not understand why the click event on the svg cannot be handled by both scripts. I assume that this has something to do with event handlers but I am not sure how I could modify the script so they both picked up the same event.
Failing that I could use the fact the visibility state changes to trigger the action.
Any guidance welcomed.
Edit Ok I have just resolved the issue with script 2 picking up the triggered event from script 1. Sad to say this was a basic error on my part ... the form was preventing the display of the alert. However I still cannot get the is(:visible) to work.
Your syntax may be off:
$("#cancellation_Form_Wrapper").is(":visible", function(){
// do stuff
});
should be:
if($("#cancellation_Form_Wrapper").is(":visible")){
// do stuff
});
EDIT: If you want something to happen after a div is made visible, you may want to use the show() callback rather than toggling visibility:
$('#cancellation_Form_Wrapper').show(timeInMilliseconds, function(){
// do something
});
However, this needs to take place in the same function, which I don't think improves your position.
The problem is probably that your second on() script is firing at the same time as your first, meaning the wrapper is not yet visible. You could try wrapping the second on() in a short timeout:
$(".booked").on("click", function() {
setTimeout(function(){
if($("#cancellation_Form_Wrapper").is(":visible")){
// do stuff
});
}, 100);
});
That should introduce enough of a delay to make sure the wrapper has been shown before trying to execute the second statement.
EDIT
Based on the number of views and the complete lack of responses I have to assume that I did a poor job of communicating my issue. I'm going to try to rectify that now.
I extended the HTMLElement prototype with a new tap method like so:
HTMLElement.prototype.tap = function (func) {
this.addEventListener("touchend", func, false);
};
I also created a custom tap event in jQuery:
$(document).delegate("*", "touchend", function (e) {
$(this).trigger("tap");
});
I also created a jQuery plugin called tap:
$.fn.tap = function (func) {
this.bind("tap", func);
};
If I try to use any of these with a callback function that includes an alert statement the callback executes twice. I tap the element to pop up the alert. I tap the "OK" button in the alert to close it. The next time I tap the screen no matter how long I wait the alert pops up again. This time tapping the "OK" button doesn't seem to set up another repeat.
However if the callback function doesn't include an alert statement (e.g. I use a console.log statement instead) the callback only executes the one time.
Does anyone know a way to deal with this? I'm about to try unhooking the event handler from within itself and then rebinding it afterwards, but that's nothing more than a hack if it's even successful.
I'd rather do things the "right" way. :-)
ORIGINAL
I just finished writing a "tap" function that I can use by extending the HTMLElement or Element prototypes as well as a custom "tap" event and "tap" plugin both for jQuery. I thought I had this in the bag until I decided to use a simple alert statement as test code.
When I use these with some element on my test page, they fire properly when I first "tap" the element, but the problem arises after I touch the alert's "OK" button and then, any amount of time later, tap the screen again at which point the event handler fires a second time.
At first I thought it was my custom code, but when I tried it with the following very basic JavaScript I was able to replicate the exact same issue.
document.getElementById("some-element").ontouchend = function (e) {
alert("Howdy doody!");
};
I imagine it must have something to do with the fact that I have to touch the screen again to execute the "OK" on the alert while still technically "inside" the event handler (since the alert is in effect "blocking" the completion of the handler function).
The fact that the behavior isn't replicated with the following slightly different code seems to support my imagination. :-)
document.getElementById("some-element").ontouchend = function (e) {
console.log("Howdy doody!");
};
If I include the above code in a page and touch that element after the callback fires I won't get a repeated firing of that callback function as opposed to the previous block of code where I'll see the alert pop up a second time the next time I tap the screen after hitting "OK" no matter where on the page I tap.
A strange issue indeed, and I haven't been able to find any information about why this might be happening. Does anyone have an idea what is happening?
I believe the visual, full-page alert being triggered on touch end is interfering with the touch event cycle. Try to call the alert after yielding to the DOM. eg.
setTimeout(function() {
alert('btn clicked');
}, 0);