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);
});
Related
This question already has answers here:
In Javascript, why is the "this" operator inconsistent?
(8 answers)
Closed 7 years ago.
so I have a few buttons and because I don't want to code the same thing for each button I was trying to make a dynamic event handler that could manage all the buttons based on the .selected-pack class but all the $(this) attributes are coming back undefined although there is a value.
This is the js:
//Function In Test!
$('.selected-pack').click(function(event) {
if($("#mainconsole").val() == "") {
alert("Select Your Console!")
return;
}
if($("#paymentmethod").val() == "") {
alert("Select Your Preferred Payment Method!")
return;
}
$("#selectConsolediv").fadeOut("medium", function() {
$("#choosePlatformLI").removeClass("active");
var packipn = $(this).attr('data-ipn');
var packipnpp = $(this).attr('data-ipnpp');
var packname = $(this).attr('data-name');
var packprice = "";
console.log(packname);
if ($("#mainconsole").val() == "PS"){
packprice = $(this).attr('data-psprice');
}
if ($("#mainconsole").val() == "XBOX") {
packprice = $(this).attr('data-xbprice');
}
// Skrill
$("#mainamount").val(packprice);
$("#mainipn").val(packipn);
$("#maindesc").val(packname);
$("#maindiscount").val($("#discount1").val());
// PayPal
$("#mainamountpp").val(packprice);
$("#mainipnpp").val(packipnpp);
$("#ppitemname").val(packname);
$("#maindiscountpp").val($("#discount1").val());
$("#checkoutPackName").text(packname);
$("#checkoutCode").text($("#discount1").val());
$("#checkoutPrice").text("£" + packprice);
$("#checkoutdiv").fadeIn("medium", function() {
$("#checkoutLI").addClass("active");
});
});
});
Do any of you spot an error? Please give me a comment as soon as possible, thanks in advance :)
It's because the scope of $(this) changes inside the fadeOut() callback. Try adding:
var self = $(this);
at the top immediately after $('.selected-pack').click(function(event) { and use self instead throughout.
So i am having trouble unhiding a div, once it has been hidden.
The code:
First object
$('#filter_region').on('change', function(e) {
var temp_region_id = $('#filter_region').val();
filterRegionId($temp_region_id);
});
Seconds object:
function filterRegionId(temp_region_id)
{
if ($(temp_region_id) != 1) {
$('.showheadline').hide(); }
else { $('.showheadline').show(); }
}
Really what i want to do, is once the region is changed from the original, the div should be hidden - this works!
However, once the person goes back on the same region, the div is still hidden.
The filter_region echos from 1-8 depending on the region. I realise that i have set the region to 1, this is to test. However, even if the if-statement is set to 1, it still shows the divs when loaded, even if the region is 2-8. Hope this make any sense at all! Please feel free to ask if there are any questions regarding my explanation.
Best Regards,
Patrick
Try this, without the $(..) around the var
$('#filter_region').on('change', function(e) {
var temp_region_id = $('#filter_region').val();
filterRegionId(temp_region_id);
});
function filterRegionId(temp_region_id)
{
if (temp_region_id != 1) {
$('.showheadline').hide();
}
else {
$('.showheadline').show();
}
}
A text input's value attribute will always return a string. You need to parseInt the value to get an integer
var temp_region_id = parseInt($('#filter_region').val(),10);
and remove the $ from variable name filterRegionId($temp_region_id); and if ($(temp_region_id) != 1) {
$('#filter_region').on('change', function(e) {
var temp_region_id = parseInt($('#filter_region').val(),10);
///parse it to integer
filterRegionId(temp_region_id);
});
function filterRegionId(temp_region_id){
if (temp_region_id!= 1)
$('.showheadline').hide();
else
$('.showheadline').show();
}
The best solution is to rewrite you code a little.
Please add the filterRegion function on top and change the parametter name as follows
var temp_region_id = $('#filter_region').val();
filterRegionId(temp_region_id);
$('#filter_region').on('change', function(e) {
temp_region_id= $('#filter_region').val();
filterRegionId(temp_region_id);
});
function filterRegionId(temp_region_id)
{
if ($(temp_region_id) != 1) {
$('.showheadline').hide();
}
else {
$('.showheadline').show();
}
}
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);
});
}
I'm using the HTML5 tag details for a FAQ section of a company. An issue was that if the user opened another question the other question would not close automatically. Therefore I searched on the web and found the following solution:
function thisindex(elm){
var nodes = elm.parentNode.childNodes, node;
var i = 0, count = i;
while( (node=nodes.item(i++)) && node!=elm )
if( node.nodeType==1 ) count++;
return count;
}
function closeAll(index){
var len = document.getElementsByTagName("details").length;
for(var i=0; i<len; i++){
if(i != index){
document.getElementsByTagName("details")[i].removeAttribute("open");
}
}
}
This code does work properly in some sense but it has some small issues. Sometimes it opens two questions at the same time and works funny. Is there a method so this can work properly? This should work on desktop, tablet and mobile.
NOT DESIRED EFFECT:
I created a fiddle http://jsfiddle.net/877tm/ with all the code. The javascript is doing it's work there, ig you want to see it live click here.
Since you tagged jQuery, you can just do this:
$('.info').on('click', 'details', function () {
$('details').removeAttr('open');
$(this).attr('open', '');
});
All this does is remove the open attribute of all detail tags when you click on any detail, and then reopen the one you just clicked on.
http://jsfiddle.net/877tm/3/
the hole thisindex function is stupid and can be removed. You can simply pass the details element to closeAll.
The closeAll is quite stupid, too it searches for details in the for loop, wow.
// closeAll
function closeAll (openDetails){
var details = document.getElementsByTagName("details");
var len = details.length;
for(var i=0; i<len; i++){
if(details[i] != openDetails){
details[i].removeAttribute("open");
}
}
}
In case you want write clean code.
You should use $.on or addEventlistener.
Try to be in a specific context and only manipulate details in this context. (What happens, if you want to have two accordion areas. Or some normal details on the same site, but not inside of the group.)
Only search for details in the group, if details was opened not closed.
Give the boolen open property some love, instead of using the content attribute
I made small fiddle, which trys to do this.
To make details as accordion tag you can use below jquery.
$("#edit-container details summary").click(function(e) {
var clicked = $(this).attr('aria-controls');
closeAll(clicked);
});
function closeAll (openDetailid){
$("#edit-container details" ).each(function( index ) {
var detailid = $(this).attr('id');
var detailobj = document.getElementById(detailid);
if (openDetailid != detailid ) {
detailobj.open = false;
}
});
$('html, body').stop().animate({ scrollTop: $('#'+openDetailid).offset().top -100 }, 1000);
}
I have a solution with jQuery
$('details').on('click', function(ev){ //on a '<details>' block click
ev.preventDefault(); //prevent the default behavior
var attr = $(this).attr('open');
if (typeof attr !== typeof undefined && attr !== false){ //if '<details>' block is open then close it
$(this).removeAttr('open');
}else{ // if '<details>' block is closed then open the one that you clicked and close all others
var $that = $(this); //save the clicked '<details>' block
$(this).attr('open','open'); //open the '<details>' block
$('details').each(function(){ //loop through all '<details>' blocks
if ($that.is($(this))){ //check if this is the one that you clicked on, if it is than open it or else close it
$(this).attr('open','open');
}else{
$(this).removeAttr("open");
}
});
}
});
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.