Recursive function causes other calls to fire multiple times - javascript

I'm working on a quiz game, wherein the user is presented with a quote and has to guess the author:
function startGame(quotes) {
askQuestion(quotes[0], 0, 0);
function askQuestion(quote, question, score) {
var q = "<span class='quo'>“</span><em>" + quote.quote + "</em><span class='quo'>”</span>";
$('.choice').css('visibility', 'visible');
$('#questions').html(q);
$('.choice').click(function(e){
$('.choice').css('visibility', 'hidden');
e.preventDefault();
var nextq = (question + 1);
var btntxt = (nextq < number_of_questions ? 'Next...' : 'Final results');
if ($(this).attr('data-author') === quote.author) {
score++;
$('#questions').html('<h1>Correct.</h1><a class="btn next">' + btntxt + '</a>');
document.getElementById('win').play();
} else {
$('#questions').html('<h1>Wrong.</h1><a class="btn next">' + btntxt + '</a>');
document.getElementById('lose').play();
}
$('#questions').append('<h4>Score: ' + score + '/' + nextq + '</h4>');
$('.next').on("click", function(){
question += 1;
if (question < number_of_questions) {
askQuestion(quotes[question], question, score);
} else {
tallyScore(score);
}
});
});
}
}
When a question is asked, the askQuestion() function is called again if fewer than 6 questions have been asked.
Everything works great, but I'm having issues with the sound effects. If a user gets an answer right and then an answer wrong, both the "win" and "lose" sound effects are played simultaneously.
My guess is that this has something to do with my recursively calling askQuestion() -- it seems like the entire "history" of the function is looped through. I was having a similar problem earlier — on correct answers, the score global variable was incremented by the number of previously correct answers (instead of just by one).
Any idea how I can fix that? Thanks!
Edit: As requested, here's a JSfiddle.

easy fix actually. you are re-attaching the click listener over and over, so just remove it each time it gets set.
change
$('.choice').click(function (e) {
to
$('.choice').off().click(function (e) {
http://jsfiddle.net/NADYM/

Every time askQuestion is called, you add an event handler to the html elements. So when you click on the .choice element, multiple events are run.
Try giving a unique id to all generated element and use that id to attach event handlers.

Related

fullcalendar.io - Holding Event in memory

I believe javascript is holding the event in memmory but I can't figure out where and how to get around it. maybe you guys can help. I have created a JSFiddle to demonstrate the problem
JSFIDDLE
So it happens when you update one event. Then you move to another event go to update that event. It brings the old event to the new event. Changes the start and end and everything. First event updates fine.
When you click event. These functions are fired.
function eventClick(calEvent){
$('#edit-event-title').val(calEvent.code);
$('#edit-event-description').val(calEvent.description);
$('#event-start-edit-dpick').data('DateTimePicker').date(calEvent.start).format('YYYY-MM-DD');
$('#event-start-time-edit-dpick').data('DateTimePicker').date(calEvent.start).format('HH:mm');
$('#event-end-edit-dpick').data('DateTimePicker').date(calEvent.end).format('YYYY-MM-DD');
$('#event-end-time-edit-dpick').data('DateTimePicker').date(calEvent.end).format('HH:mm');
$('#fc_edit').click();
}
function createUpdateEvent(calEvent, create) {
//create event
if(create){
// create the event
} else {
$(".antosubmit2").on("click", function() {
calEvent.code = $("#edit-event-title").val();
calEvent.title = $("#edit-event-title option:selected").html();
calEvent.description = $("#edit-event-description").val();
calEvent.start = moment($('#event-start-edit-dpick').data('DateTimePicker').date().format('YYYY-MM-DD') + ' ' +
$('#event-start-time-edit-dpick').data('DateTimePicker').date().format('HH:mm') +
$('#event-start-edit-dpick').data('DateTimePicker').date().format('Z'));
calEvent.end = moment($('#event-end-edit-dpick').data('DateTimePicker').date().format('YYYY-MM-DD') + ' ' +
$('#event-end-time-edit-dpick').data('DateTimePicker').date().format('HH:mm') +
$('#event-end-edit-dpick').data('DateTimePicker').date().format('Z'));
calendar.fullCalendar('updateEvent', calEvent);
$('.antoclose').click();
});
}
}
function recalcHeaderHours(event){
var currentday = moment(event.start).format("YYYY-MM-DD");
if (event.totalHours > 0) {
var prev = $("#dailytotal-"+currentday).text() || 0;
$("#dailytotal-"+currentday).text(+prev + +event.totalHours);
}
}
I hope you guys can assist. Thanks for your time :)
I fixed your issue.
The problem is that you put the on click event to the ".antosubmit2" in line 83. On first event open there will be 1 click on this class, but on the 2. event open the code put another click on it. If you open only one event 2 times, there will be no problem. But it you do it on different events, on the second open, 2 click fires on it. The newly added click use correct data, but the first click use the first event datas. This is your problem I guess.
The first click should be unbind from the ".antosubmit2".
Try to modify your code like this:
function createUpdateEvent(calEvent, create) {
//create event
if(create){
// create the event
} else {
$(".antosubmit2").unbind('click');
$(".antosubmit2").on("click", function() {...
You see the "unbind('click')" line, add it to the code and it will works.

jQuery function running multiple times despite input being disabled?

I'm having an issue where a function (and subsequent callback functions) continue to run after the first keypress, despite the fact that I'm specifically disabling the input and unbinding keypress. The weird thing is, these additional results only start appearing after a significant amount of time has passed (10+ seconds I would guess). You can see this error in action by going to http://isitsketch.com and mashing on the enter button while entering an address. The relevant code is this:
$('.location-form').keypress(function(event){
if (event.which == 13){
$(this).find('input').attr('disabled','disabled');
$(window).unbind("keypress")
console.log('search entered')
event.preventDefault();
userAddress = $("#input1").val()
address = userAddress.replace(/\s+/g, '+');
getMaps(address)
event.stopPropagation()
return false;
} else {
return true;
}
});
The function that displays the results is this:
function displayResults(sketchLevel, robberies, assaults, burglaries, thefts, weapons, topFiveArr) {
$('#newResults').append('<h4 id="feedback" style="color:white;text-align:center;">' + userAddress + '</h4>')
$("<h2 id='result-level'>Sketch Level: <span class='redText'>"+ sketchLevel +"</span></h2>").appendTo("#newResults")
$('<div id="indicator"><div id="bar"></div><div id="dial"></div></div>').appendTo("#newResults")
$('<a id="tryAgain" class="waves-effect waves-light btn" href="http://isitsketch.com">Enter a New Address</a>').appendTo("#newResults")
$('<p id="explanation">These results are based on NYC\'s OpenData information platform. The crimes have been weighted to reflect their severity. The resulting SketchLevel ranges from 0 (no crimes) to 2000+ (lots of severe crime activity).</p>').appendTo("#newResults")
$('#newResults').append('<h4 id="topFive">Can you beat these scores?:</h4><ul id="topList"></ul>')
for (i = 0; i < 5; i++){
var currentTopArea = topFiveArr[i]['area']
var currentTopRank = topFiveArr[i]['rank']
$('#topList').append('<li style="color:white; font-size:1em;">' + currentTopArea + ': ' +'<span id="rankText">' + currentTopRank + '</span>' +'</li>')
}
var audio = new Audio('sound/gunsound.mp3')
audio.play();
if(sketchLevel <= 400) {
$('#dial').addClass('sketchlevel1')
}
if(sketchLevel > 400 && sketchLevel <= 800) {
$('#dial').addClass('sketchlevel2')
}
if(sketchLevel > 800 && sketchLevel <= 1400){
$('#dial').addClass('sketchlevel3')
}
if(sketchLevel > 1500 && sketchLevel <= 2000) {
$('#dial').addClass('sketchlevel4')
}
if(sketchLevel > 2000) {
$('#dial').addClass('sketchlevel5')
}
}
Since the keypress event handler is bound to .location-form, you need to unbind it from that element, not window. So it should be:
$('.location-form').unbind("keypress");
Also, .off() is preferable to .unbind(), unless you need to be compatible with jQuery versions before 1.7.
I figured out how to stop it, although I still don't know why it was occurring in the first place. The fix was this:
var enabled = true;
displayResults(){
if (enabled) {
...the rest of the code here
enabled = false;
}
}
That said, it would be awesome if somebody else could figure out how/why it was getting around the input-disabled line and then continuing to post every 10 seconds or so. Just so weird.

Unable to change text on onclick

I have a codepen at http://codepen.io/templenaylor/pen/ggoMPZ?editors=0011
I am currently displaying a temperature that references a var:
<ul>
<li id="fTemp"></li>
</ul>
When trying to change it by clicking it, it will not work. This is the function I am using to do that:
$("#fTemp").click(function(){
if(tempSwap===false){
$("#fTemp").html(fTemp + " ℉");
tempSwap=true;
} else{
$("fTemp").html(cTemp + " ℃");
tempSwap=false;
}
});
Is there something I am not seeing within my function that is incorrect?
As pointed out by #MichaelCoker, you are missing the # in your else branch.
In addition to fixing that, I would save the element to a variable to help prevent errors in the future.
var ftemp_li = $("#fTemp");
ftemp_li.click(function(){
if(tempSwap == false){
ftemp_li.html(fTemp + " ℉");
tempSwap = true;
} else {
ftemp_li.html(cTemp + " ℃");
tempSwap = false;
}
});
http://codepen.io/anon/pen/VPyNPO?editors=0011
You are not referencing the correct selector in your else block
} else{
$("fTemp").html(
is supposed to be
} else{
$("#fTemp").html(
Also you seem to binding the click event every single time your ajax is successful.
Move it out of the callback and bind your click event in DOM ready handler.

Javascript Multiple Divs same classname but different id's. Always returns last div on clicking any of them

I feel silly asking this question. I have a javascript problem that I have been trying to solve since spring break.
I dynamically create divs to contain ratings for a product. But when I click on one of them, it always returns the last one.
for(var i=0; i < 5; i++) {
// Create Class called divReview
var divReview = document.createElement("div");
divReview.className = "divReview";
counter_ratings++;
var s = counter_ratings.toString();
divReview.id = "ratings" + s;
divReview.innerHTML = divReview.id;
$( divReview ).click(function() {
alert("You clicked " + divReview.innerHTML);
});
mainContainer.appendChild(divReview);
}
Here's the fiddle:
http://jsfiddle.net/alvasay/a9GZq/4/
I am pretty sure this is a simple problem, but I just can't see where I'm doing wrong. Thanks!
As mglison said, late binding. Alternative solution though is to use this in place of divReview in your click handler to reference the element being clicked.
$( divReview ).click(function() {
alert("You clicked " + this.innerHTML);
});
http://jsfiddle.net/a9HAH/
You're experiencing late binding. At the time the function is called, the value of divReview is the last value it had in the loop. I've solved it by creating a function which wraps the actual function to return so that you get the correct value from the closure:
Essentially, the code is something like:
for (...) {
...
var funcMaker = function(divRev) {
return function() {
alert("you clicked " + divRev.innerHTML);
};
};
$( divReview ).click(funcMaker(divReview));
}
http://jsfiddle.net/a9GZq/9/
Apart from the problem mentioned by mgilson, you have an odd mix of plain JS and jQuery. Here's a shorter version
for (var i = 1; i < 6; i++) {
var divReview = $('<div id="ratings' + i + '" class="divReview">ratings' + i + '</div>');
$('#gameContainer').append(divReview);
divReview.click(function() {
alert("You clicked " + this.innerHTML);
});
}

$(document).on("click"... only working occasionally [duplicate]

This question already has an answer here:
jQuery on(): strange behaviour
(1 answer)
Closed 9 years ago.
I am trying to create a script that updates a variable with the last-clicked element every time a div with the class furniture gets clicked.
Unfortunately, while it seems that this does work, It only appears to be working sometimes. And as far as consistency of any sort is concerned I have been unable to find any.
$(document).on("click", ".furniture", function() {
console.log("YouBeClickin'");
if ( isCurrentElem == 1) {
$(currentElem).removeClass("chosen")
}
currentElem = "#" + this.id;
$(currentElem).addClass( "chosen");
isCurrentElem = 1;
//alert(currentElem);
});
I am adding my furniture classed elements dynamically with JavaScript, otherwise I would post up the HTML. Upon inspecting the HTML, it is apparent that my divs to get classed with furniture so the problem doesn't lie there.
The click appears to never actually fire, noted not by the fact that I don't get the expected results on screen, but that nothing get's logged in my console. Again, it's not that it never happens just that it happens super infrequently.
Any help would be greatly appreciated.
You probably want something like this:
var currentFurniture; // predefine the "global"
$(document).on("click", ".furniture", function () {
console.log("YouBeClickin'");
if ( currentFurniture !== this ) {
$(currentFurniture).removeClass("chosen");
currentFurniture = this;
$(this).addClass("chosen");
}
});
Try:
$(document).bind(function() {
console.log("YouBeClickin'");
if ( isCurrentElem == 1) {
$(currentElem).removeClass("chosen")
}
currentElem = "#" + this.id;
$(currentElem).addClass( "chosen");
isCurrentElem = 1;
//alert(currentElem);
});
or with Jquery:
$(document).onclick(function() {
console.log("YouBeClickin'");
if ( isCurrentElem == 1) {
$(currentElem).removeClass("chosen")
}
currentElem = "#" + this.id;
$(currentElem).addClass( "chosen");
isCurrentElem = 1;
//alert(currentElem);
});

Categories