Change a global variable from inside an if-function - javascript

I have a hotspot image thingy thing where you got spots (called "items") hovering on the image which are clickable. When you click such an item, a textbox appears on the right side of the image with all the information. Now if you click another item, the textbox should close and a new one opens up.
This is the current code:
jQuery(document).ready(function() {
counter = 1;
var lastHotspot = 0;
jQuery("#{{item.item_id}}").click(function(){
if (counter == 1) {
jQuery("#textbox{{item.item_id}}").show();
lastHotspot = {{item.item_id}};
counter++;
} else {
jQuery("#textbox" + lastHotspot).hide();
jQuery("#textbox{{item.item_id}}").show();
lastHotspot = {{item.item_id}};
}
});
});
Because there isn't a textbox the first time everything loads, I want to run the ".show" on the textbox the first time you click an item and then store the item's ID. After that, when I click an item, it should ".hide" the textbox of the previous item, then ".show" the next textbox from the clicked item and then re-assign the item-ID to "lastHotspot" and then repeat everytime an item gets clicked.
The problem I have is, that "lastHotspot" doesnt get stored inside the variable after getting re-assigned inside the if-function, even tho the counter does.
How can I fix this issue?

You can either bind the functions before you attach them to the click events, or you can use a global object to modify the counters:
jQuery(document).ready(function() {
counter = 1;
var lastHotspot = 0;
jQuery("#{{item.item_id}}").click((function(){
if (counter == 1) {
jQuery("#textbox{{item.item_id}}").show();
lastHotspot = {{item.item_id}};
counter++;
} else {
jQuery("#textbox" + lastHotspot).hide();
jQuery("#textbox{{item.item_id}}").show();
lastHotspot = {{item.item_id}};
}
}).bind(this));
});
Using global Object:
jQuery(document).ready(function() {
configs = { counter: 1 };
var lastHotspot = 0;
jQuery("#{{item.item_id}}").click(function(){
if (configs.counter == 1) {
jQuery("#textbox{{item.item_id}}").show();
lastHotspot = {{item.item_id}};
configs.counter++;
} else {
<...>
}
});
});

Related

Prevent actions before setTimeout() is over

Im curently making a memory game and if two card matches it blocks them but if not they should flip back. The problem is that you can click on other cards even if there are two cards already flipped and if you click more cards the game goes crazy and stops working
Any idea?
here's the code
https://codepen.io/stivennpe/pen/KRxvxR?editors=1010
restart ();
bindcards();
// to restart the game and shuffle the cards
function restart() {
$('.restart').on('click', function () {
cards = shuffle($('.card'));
$(".card").each(function() {
$( this ).removeClass( "open match show" );
});
$('.deck').html(cards);
bindcards();
});
}
//to open/show the card
function bindcards(){
$('.card').click(function () {
$(this).addClass('open show');
let openCards = $('.open');
let list = jQuery.makeArray(openCards);
if (list.length === 2 && list[0].innerHTML ===
list[1].innerHTML){
$(openCards).addClass('match');
}
if (list.length === 2) {
setTimeout(hola, 1000)
function hola() {$(openCards).removeClass('open show');
}
}
});
}
thanks
Seems like for a simple solution you could set a global variable, something like blockClicks
If blockClicks is true, do nothing when a user clicks. Reset its value to false after timeout
There is a race condition between applying the .open class to the div element, refreshing the page, querying that element, and the user speeding their way through your game. Instead of adding the .open class to the div, hoping the page refreshes quick enough, then immediately querying against with to find out how many open cards you have, keep a local variable count. Below is the slight modification to your code
function bindcards() {
let numOfOpenCards = 0;
$(".card").click(function(e) {
++numOfOpenCards;
if(numOfOpenCards > 2)
return;
$(this).addClass("open show");
let openCards = $(".open");
let list = jQuery.makeArray(openCards);
if (numOfOpenCards >= 2 && list && list.length >= 2 && list[0].innerHTML === list[1].innerHTML) {
$(openCards).addClass("match");
}
if (numOfOpenCards >= 2) {
setTimeout(hola, 1000);
function hola() {
numOfOpenCards = 0;
let openCards = $(".open");
let list = jQuery.makeArray(openCards);
if(list) {
for(let i = 0; i < list.length; ++i)
$(list[i]).removeClass("open show");
}
}
}
});
}
If two cards are already open, the most recent card check. The previous card check should still complete and refresh as needed.
https://codepen.io/anon/pen/NzPBrB?editors=1010
Additional edit
If you do not want to use numOfOpenCards, you can use the following. Find how many are already open. If there are more than 2 already, just quit. If there are less than already flipped, add the class then query the DOM again. Anywhere numOfCards is used you can replace with list.length;
let openCards = $(".open");
let list = jQuery.makeArray(openCards);
if(list && list.length > 2)
return;
$(this).addClass("open show");
openCards = $(".open");
list = jQuery.makeArray(openCards);
if (list.length >= 2) {
setTimeout(hola, 1000);
function hola() {
$(list).removeClass('open show');
}
}

If statement does not work when condition is met

Here is my code:
var count = 2;
var decrementAmount = 1;
function reduceVariable() {
count -= decrementAmount;
}
$("#button").click(function() {
reduceVariable();
});
if (count == 0) {
$("#avrageReactionTime").html("Hello");
};
When i click my button twice the div that has the id avrageReactionTime does not change to have the text hello. Why do i have this problem...
Right now you test once, instead of testing every time the counter changes.
You must put the if inside the event handler :
$("#button").click(function() {
reduceVariable();
if (count==0) {
$("#avrageReactionTime").html("Hello");
}
});
Note that properly indenting your code makes it obvious.

Change image src back and forth after first click

What I want to happen is... when the image 'x' is clicked i want it to change image then when it is clicked again i want it to change back so on and so fourth, however I only want this to happen on the second click.
So X is clicked & nothing happens,
Then when it is clicked again it changes images,
and then back after another click, and then it alternates back and forth after that,
until the page resets, then i want it to reset as well.
this is my code so far:
document.getElementById('x').onclick = function() {
var ClickedOnce = 0;
if (this.src == 'Media/Images/Other/SwitchUP.jpg') {
ClickedOnce + 1
}
if (this.src == 'Media/Images/Other/SwitchUP.jpg' && ClickedOnce > 1) {
this.src = 'Media/Images/Other/SwitchDOWN.jpg';
} else if ('Media/Images/Other/SwitchDOWN.jpg') {
this.src = 'Media/Images/Other/SwitchUP.jpg';
}
}
It looks like the reason this isn't working is because you are declaring the var ClickedOnce inside of a function. This means that it is a local variable inside that function that will be set to 0 every time that function is called. Therefore, the same thing will happen every time it is clicked.
Try declaring some variable outside of the function.
You can try something like this:
var wasClicked = false;
document.getElementById('x').onclick = function() {
if (!wasClicked) {
wasClicked = true;
return;
}
if (this.getAttribute("src") == 'Media/Images/Other/SwitchUP.jpg') {
this.setAttribute("src", 'Media/Images/Other/SwitchDOWN.jpg');
} else {
this.setAttribute("src", 'Media/Images/Other/SwitchUP.jpg');
}
}
Additionally, since you tagged this question with jQuery, here is a jQuery approach to it:
var wasClicked = false;
$(document).ready(function() {
$("#x").click(function() {
if (!wasClicked) {
wasClicked = true;
return;
}
if ($(this).attr("src") == "path/to/some/image") {
$(this).attr("src", "path/to/other/image");
} else {
$(this).attr("src", "path/to/some/image");
}
});
});

Content Click Counter

I need to count the number of clicks on a piece of content - after which, I need to run a certain function.
I can't run the function on every click, only after the user finishes their desired clicks.
The amount of clicks needs to be 1, 2, or 3 and above, where I only want to do something on one or two clicks, and ignore anything else.
Note I only need to run the function after the clicks, then reset the counter.
I've tried the following, but it logs 'single' after every click.
var clicks = 0;
$(controller).click(function() {
var elem = this, $elem = jQuery(elem), clicks = $elem.data('clicks') || 0;
clicks += 1;
// Reset triple click counter if no click is made within 500ms
setTimeout(function() {
clicks = 0;
}, 500);
setTimeout(function() {
if (clicks >= 3) {
console.log("triple or more");
}
if (clicks === 2) {
console.log("double");
}
if (clicks === 1) {
console.log("single");
}
}, 200);
});
Here is a JSBin example
It's a little hard to see what you want to happen after 3 clicks, do you want to trigger triple clicks for each of them or not.
I created a version that you might want to look at: http://jsbin.com/dutilojujowa/5/edit
The ideas are:
Save all the click counter data into the data attribute instead of relying on scope - I find that easier.
Throttle your reset counter, otherwise multiple clicks can be handled very strangely
Throttle your action counter, or you might get multiple actions accidentally!
Make sure you set $elem.data('clicks') to 1 at some point, or it won't work.
You need to update $elem.data('clicks') at the end of your function. See http://css-tricks.com/snippets/jquery/triple-click-event/
Can you try following code:
var totalCount;
var intervalVar;
var ShowResultVar;
function HandleClicks() {
totalCount = totalCount + 1;
}
function ShowResult() {
if(totalCount == 0)
{
console.log("No Clicks");
}
else if (totalCount == 1)
{
console.log("One Click");
}
else if(totalCount == 2)
{
console.log("Two Clicks");
}
else if (totalCount >2) {
console.log("Three or more Clicks");
}
}
$(document).ready(function () {
totalCount = 0;
$("#myControl").bind("click", HandleClicks);
intervalVar = setInterval(function () {
totalCount = 0;
}, 500);
ShowResultVar = setInterval(function () {
ShowResult();
}, 200);
});
It is working for me. Output is as follows:
No Clicks
No Clicks
No Clicks
No Clicks
No Clicks
No Clicks
No Clicks
No Clicks
No Clicks
No Clicks
One Click
Two Clicks
One Click
Two Clicks
No Clicks
One Click
Two Clicks
No Clicks
One Click
Two Clicks
Two Clicks
Three or more Clicks
One Click
One Click
No Clicks
No Clicks
No Clicks
No Clicks
No Clicks
Try this-
$("#content").data('clicks', 0);
$("#content").click(function () {
var elem = this,
$elem = jQuery(elem);
var clicks = $elem.data('clicks') + 1
$elem.data('clicks', clicks);
if (clicks == 1) {//start re-setter and counter when first click
setTimeout(function () {
$elem.data('clicks', 0);
}, 500);
setTimeout(function () {
var clicks = $elem.data('clicks');
if (clicks >= 3) {
console.log("triple or more");
}
if (clicks === 2) {
console.log("double");
}
if (clicks === 1) {
console.log("single");
}
}, 200);
}
});
DEMO

IE7 issues with my jQuery [click and change functions]

I have the following snippets of code. Basically what I'm trying to do is in the 1st click function I loop through my cached JSON data and display any values that exist for that id. In the 2nd change function I capturing whenever one of the elements changes values (i.e. yes to no and vice versa).
These elements are all generated dynamically though the JSON data I'm receiving from a webservice. From my understanding that is why I have to use the .live functionality.
In Firefox everything works as expected (of course). However, in IE7 it does not. In IE7, if I select a radio button that displays an alert from the click function then it also adds to the array for the changed function. However, if the radio button does not do anything from the click function then the array is not added to for the change.
As I look at this code I'm thinking that I might be able to combine these 2 functions together however, right now I just want it to work in IE7.
$(document).ready(function () {
//This function is run whenever a 'radio button' is selected.
//It then goes into the CPItemMetaInfoList in the cached JSON data
//($.myglobals) and checks to see if there are currently any
//scripts to display.
$("input:radio").live("click", function () {
var index = parseInt(this.name.split(':')[0]);
for (i = 0; i <= $.myglobals.result.length - 1; i++) {
if ($.myglobals.result[i].CPItemMetaInfoList.length > 0) {
for (j = 0; j <= $.myglobals.result[i].CPItemMetaInfoList.length - 1; j++) {
if (index == $.myglobals.result[i].QuestionId) {
alert($.myglobals.result[i].CPItemMetaInfoList[j].KeyStringValue);
return;
}
}
}
}
});
});
$(document).ready(function () {
var blnCheck = false;
//Checks to see if values have changed.
//If a value has been changed then the isDirty array gets populated.
//This array is used when the questionSubmit button is clickeds
$('input').live('change', function () {
blnCheck = false;
for (i = 0; i <= isDirty.length - 1; i++) {
if (isDirty[i] == $(this).attr("name")) {
blnCheck = true;
break
}
}
if (blnCheck == false) {
isDirty[arrayCount] = $(this).attr("name");
arrayCount += 1;
alert($(this).attr("name"));
}
});
$('textarea').live('change', function () {
blnCheck = false;
for (i = 0; i <= isDirty.length - 1; i++) {
if (isDirty[i] == $(this).attr("id")) {
blnCheck = true;
break
}
}
if (blnCheck == false) {
isDirty[arrayCount] = $(this).attr("id");
arrayCount += 1;
//alert($(this).attr("name"));
}
});
});
UPDATE:
I had to move this chunk of code into the click function:
blnCheck = false;
for (i = 0; i <= isDirty.length - 1; i++) {
if (isDirty[i] == $(this).attr("name")) {
blnCheck = true;
break
}
}
if (blnCheck == false) {
isDirty[arrayCount] = $(this).attr("name");
arrayCount += 1;
alert($(this).attr("name"));
}
Like this:
$(document).ready(function () {
//This function is run whenever a 'radio button' is selected.
//It then goes into the CPItemMetaInfoList in the cached JSON data
//($.myglobals) and checks to see if there are currently any
//scripts to display.
$("input:radio").live("click", function () {
var index = parseInt(this.name.split(':')[0]);
for (i = 0; i <= $.myglobals.result.length - 1; i++) {
if ($.myglobals.result[i].CPItemMetaInfoList.length > 0) {
for (j = 0; j <= $.myglobals.result[i].CPItemMetaInfoList.length - 1; j++) {
if (index == $.myglobals.result[i].QuestionId) {
alert($.myglobals.result[i].CPItemMetaInfoList[j].KeyStringValue);
return;
}
}
}
}
blnCheck = false;
for (i = 0; i <= isDirty.length - 1; i++) {
if (isDirty[i] == $(this).attr("name")) {
blnCheck = true;
break
}
}
if (blnCheck == false) {
isDirty[arrayCount] = $(this).attr("name");
arrayCount += 1;
}
});
});
But...
I had to leave the change function the same. From my testing I found that the .click function worked for IE7 for the radio buttons and checkbox elements, but the .change functionality worked for the textboxes and textareas in IE7 and FF as well as the original functionality of the radio buttons and checkbox elements.
This one got real messy. Thanks to #Patricia for looking at it. Here suggestions did lead me to this solution. I'm going to leave the question unanswered as I wonder if there isn't a cleaner solution to this.
Fact: change event on radio buttons and checkboxes only get fired when the focus is lost (i.e. when the blur event is about to occur). To achieve the "expected" behaviour, you really want to hook on the click event instead.
You basically want to change
$('input').live('change', function() {
// Code.
});
to
$('input:radio').live('click', functionName);
$('input:not(:radio)').live('change', functionName);
function functionName() {
// Code.
}
(I'd however also take checkboxes into account using :checkbox selector for the case that you have any in your form, you'd like to treat them equally as radiobuttons)
I think this is because IE fires the change when focus is lost on checks and radios. so if the alert is popping up, focus is being lost and therefor the change event is firing.
EDIT:
try changing the $('input') selector to $('input:not(:radio)')
so the click will fire for your radios and the change for all your others.
Edit #2:
How bout putting the stuff that happens on change into a separate function. with the index as a parameter. then you can call that function from the change() and the click(). put the call to that function after your done with the click stuff.
You're declaring your blnCheck variable inside one of your document.ready() functions. You don't need two of these either, it could all be in one.
This means that the variable that you're declaring there won't be the one used when your change function is actually called, instead you're going to get some kind of implicit global. Don't know if this is part of it, but might be worth looking at. You should declare this at the top of your JS file instead.

Categories

Resources