OnClick propagation when generating divs with jQuery - javascript

I am not sure why the event StopPropagation technique is not working with this simple onClick example - the event seems to be bubbling up the DOM tree and is also iterating exponentially every time I click again.
I think this is because I generate html with a javascript function, and I'd be very eager to hear why you think this isn't working as expected.
EDIT: I have created a jsFiddle at http://jsfiddle.net/Guill84/GsLtN/22/. The issue becomes very clear. If I click on 'Text1' the first time, the alert pop-up comes up only once. If I click it again, it then comes up twice. If I click it again, it comes up three times, and so on. How can I amend the script so that it is run only once? This is driving me barmy.
HTML
<body>
<div id='container'>
<div id='1'>Text1</div>
<div id='2'>Text2</div>
</div>
</body>
Javascript
$(function notice_it(declim) {
if ($.isNumeric(declim)) {
//stuff
} else {
declim = 10;
}
$("#container").html("<div id='1'>Text1</div><div id='2'>Text2</div>");
alert(declim);
$('body').on('click', '#1', function (event) {
event.stopPropagation();
var declim = 10 - 1;
notice_it(declim);
});
$('body').on('click', '#2', function (event) {
event.stopPropagation();
var declim = 10 + 1;
notice_it(declim);
});
$('body').on('click', 'body', function (e) {
e.stopPropagation();
});
});

I have already added comment but then I thought this would explain in a better way.
Issue
$(function notice_it(declim) {
if ($.isNumeric(declim)) {
//stuff
} else {
declim = 10;
}
$("#container").html("<div id='1'>Text1</div><div id='2'>Text2</div>");
alert(declim);
$('body').on('click', '#1', function (event) {
event.stopPropagation();
var declim = 10 - 1;
notice_it(declim); // Issue
});
});
Here notice_it() is used to initialize events and it is called again in event handlers. Following is an updated JSFiddle - Issues showing different registered events.
Solution
A simple solution would be to migrate the code used to notify to a separate function, as done in following JSFiddle - Solution1.
A better way to implement though would be like this: JSFiddle - Solution2. It is somewhat Declarative Programming and makes it very easy for another person to understand.

Calling return false should work in your scenario.

$(function notice_it(declim) {
if ($.isNumeric(declim)) {
//stuff
} else {
declim = 10;
}
$("#container").html("<div id='1'>Text1</div><div id='2'>Text2</div>");
alert(declim);
$('body').on('click', '#1', function (event) {
return false;
var declim = 10 - 1;
notice_it(declim);
});
$('body').on('click', '#2', function (event) {
return false;
var declim = 10 + 1;
notice_it(declim);
});
$('body').on('click', 'body', function (e) {
e.stopPropagation();
});
});
Try to return false on click

Related

Onlick event not triggering which contains blur function

I have a form and on click on an input, I'm adding classes to that input's wrapped div.
To do this, I've made use of blur and executing my function on click. However, on some cases (very rarely) it will work (and add the class). But majority of the time, it doesn't perform the click action (because the console.log("click") doesn't appear).
My thinking is that maybe the browser is conflicting between the blur and click. I have also tried changing click to focus, but still the same results.
Demo:
$(function() {
var input_field = $("form .input-wrapper input");
$("form .input-wrapper").addClass("noData");
function checkInputHasValue() {
$(input_field).on('blur', function(e) {
var value = $(this).val();
if (value) {
$(this).parent().closest(".input-wrapper").removeClass("hasData noData").addClass("hasData");
} else {
$(this).parent().closest(".input-wrapper").removeClass("hasData noData").addClass("noData");
}
});
}
$(input_field).click(function() {
checkInputHasValue();
console.log("click");
});
});
i've done some modification in your code .
function checkInputHasValue(e) {
var value = $(e).val()
if (value) {
$(e).parent().closest(".input-wrapper").removeClass("hasData noData").addClass("hasData");
} else {
$(e).parent().closest(".input-wrapper").removeClass("hasData noData").addClass("noData");
}
}
$(document).on('blur',input_field, function(e) {
checkInputHasValue($(this));
});
$(document).on("click",input_field,function() {
checkInputHasValue($(this));
console.log("click");
});
In order to avoid conflits between events, you would separate the events and your value check. In your code, the blur event may occur multiple times.
The following code seems ok, as far as I can tell ^^
$(function() {
var input_field = $("form .input-wrapper input");
$("form .input-wrapper").addClass("noData");
function checkInputHasValue(el) {
let target = $(el).closest(".input-wrapper");
var value = $(el).val();
$(target).removeClass("hasData noData");
$(target).addClass(value.length == 0 ? "noData" : "hasData");
console.log("hasData ?", $(target).hasClass("hasData"));
}
$(input_field).on("click", function() {
console.log("click");
checkInputHasValue(this);
});
$(input_field).on("blur", function() {
checkInputHasValue(this);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
<div class="input-wrapper">
<input>
</div>
</form>

jquery ignoring first click

I have this function:
NewShowHideDiv2(iconID, divID, disabled) {
var x = document.getElementById(divID);
var y = document.getElementById(iconID);
$(eval(y)).click(function() {
console.log(eval(y));
$(eval(y)).toggleClass( "clicked" );
});
$(eval(x)).slideToggle("slow", function() {
});
}
All i am trying to get it to do is toggle the "clicked" class on click. However, it ignores the first and second click, and then applies it on the third and all subsequent odd number clicks. any ideas?
Without knowing how NewShowHideDiv2 is called it's difficult to be certain but there are some likely issues.
First, by putting your click binding function inside another function, the event isn't bound to the element until NewShowHideDiv2 is run. So you'll want to pull that out and put it in something like this:
$( document ).ready(function() {
$(eval(y)).click(function() {
console.log(eval(y));
$(eval(y)).toggleClass( "clicked" );
});
});
Also, the eval approach on the JS object is likely causing issues and certainly isn't the best practice. You'll want to modify that to be:
$( document ).ready(function() {
$("#iconIDHere").click(function() {
console.log(this);
$(this).toggleClass( "clicked" );
});
function NewShowHideDiv2(divID, disabled) {
$("#" + divID).slideToggle("slow", function() {
});
}
});
Try this with vanilla JS:
var x = document.getElementById('divID');
x.addEventListener('click', function(e) {
if(e.target.classList.contains('clicked')) {
e.target.classList.remove('clicked');
} else {
e.target.classList.add('clicked');
}
});
I think JQuery is:
$('#divID').click(function() {
$('#divID').toggleClass('clicked');
});

Jquery click handler is stuck in infinite loop

I have an handler on clicking an element. It is getting stuck in an infinite loop. How can I turn off the listener for the 2nd click in this code... so that it doesn't keep repeating.
I'm trying to automatically close the toggle after 4.5 seconds. But the close click triggers another click... and so on...
$(document).ready(function(){
$(".navbar-toggle").click(function() {
setTimeout(function () {
$(".navbar-toggle").click();
}, 4500);
});
});
Add a 'flag' variable to your code
var has_clicked = false;
$(document).ready(function(){
$(".navbar-toggle").click(function() {
if(!has_clicked){
setTimeout(function () {
has_clicked = true;
$(".navbar-toggle").click();
}, 4500);
}
});
});
$(function(){
function callback2(){
$("#test").one("click", callback1);
}
function callback1(){
console.log('hi');
setTimeout(callback2, 4500);
}
$("#test").one("click", callback1);
});
jsFiddle Demo
Is this similar to what you want?
Attach the click event which execute only once, using .one(),
do whatever you want in the callback function, and attach it again after 4.5 seconds. If you cannot even modify your code to this, please let me know, I will try to think another work around
This is what I am going with for now though I believe I will use shole's approach when I get some more time... for now this is working well.
var is_open = false;
$(document).ready(function(){
$(".navbar-toggle").click(function() {
if(!is_open){
setTimeout(function () {
is_open = true;
$(".navbar-toggle").click();
is_open = false;
}, 3500);
}
});
});

Need help in using .on in jquery so that it can work with dynamic data also

I have a function "single_double_click" and I am invoking the same via $('#packagelisttable tr').single_double_click(fn), which works fine with static data.
However it is not responding when I am deploying the same application to work with dynamic data.
I tried using .on also as mentioned in several posts but then also no success.Please find the same below:
$(#packagelisttable ).on('single_double_click', 'tr', fn)
$(document).on('single_double_click', 'packagelisttable tr', fn)
I need to click on a row of table (#packagelisttable) and need to check whether it was a single or double click.
Please find the code which I am using:
jQuery.fn.single_double_click = function (single_click_callback, double_click_callback, timeout) {
return this.each(function () {
var clicks = 0,
self = this;
jQuery(this).click(function (event) {
clicks++;
if (clicks == 1) {
setTimeout(function () {
if (clicks == 1) {
single_click_callback.call(self, event);
} else {
double_click_callback.call(self, event);
}
clicks = 0;
}, timeout || 300);
}
});
});
}
//$(#packagelisttable ).on('single_double_click', 'tr', function(){
//$(document).on('single_double_click', 'packagelisttable tr', function(){
// $('#packagelisttable tr').single_double_click(function () {
alert("Try double-clicking me!")
},
function () {
alert("Double click detected")
});
The delegated event version of on is used for events, but single_double_click is not an event. It is a function.
It is not possible to connect a jQuery plugin/function to a dynamically loaded elements that way.
You either need to connect any new elements to your plugin after load, or change the plugin to use classes (e.g. class="singleordouble") and use a delegated click event handler, or you can add a selector as an additional parameter and attach to a non-changing ancestor element (as Cerlin Boss demonstrates).
e.g.
jQuery(document).on('click', '.singleordouble', function (event) {
But if you do that, using a plugin becomes pointless.
It is more flexible to generate your own custom click events, using the settimeout trick you already have.
Here is a full example using custom events: http://jsfiddle.net/TrueBlueAussie/wjf829ap/2/
Run this code once anywhere:
// Listen for any clicks on the desired
$(document).on('click', '.singleordouble', function (e) {
var $this = $(this);
var clicks = $this.data("clicks") || 0;
// increment click counter (from data stored against this element)
$(this).data("clicks", ++clicks);
// if we are on the first click, wait for a possible second click
if (clicks == 1) {
setTimeout(function () {
var clicks = $this.data("clicks");
if (clicks == 1) {
$this.trigger("customsingleclick");
} else {
$this.trigger("customdoubleclick");
}
$this.data("clicks", 0);
}, 300);
}
});
It will generate custom events (called customsingleclick and `customdoubleclick in this example, but call them whatever you want).
You can then simply listen for these custom events:
$(document).on('customsingleclick', function(e){
console.log("single click on " + e.target.id);
});
$(document).on('customdoubleclick', function(e){
console.log("double click on " + e.target.id);
});
Or using delegated event handlers: http://jsfiddle.net/TrueBlueAussie/wjf829ap/3/
$(document).on('customsingleclick', '.singleordouble', function(){
console.log("single click on " + this.id);
});
$(document).on('customdoubleclick', '.singleordouble', function(){
console.log("double click on " + this.id);
});
how about this
I have made some small changes to your code. Not sure if this will work for you.
I have added one more parameter which takes a selector. Please comment if you have any doubt.
jQuery.fn.single_double_click = function (selector, single_click_callback, double_click_callback, timeout) {
return this.each(function () {
var clicks = 0,
self = this;
jQuery(this).on('click', selector, function (event) {
clicks++;
if (clicks == 1) {
setTimeout(function () {
if (clicks == 1) {
single_click_callback.call(self, event);
} else {
double_click_callback.call(self, event);
}
clicks = 0;
}, timeout || 300);
}
});
});
}
Usage :
$('#headmnu').single_double_click('li',
function () {
; // not doing anything here
}, function () {
alert('twice')
});
Here li is the child of the first jquery selector($('#headmnu')) which is a ul
This will work with dynamically added elements also.
UPDATE
Just to clarify $('#headmnu') is a parent element of all lis.
I have used event delegation here to achieve this. Please refer the documentation for more info
I checked your code and if you have pasted, then you should also check
$(#packagelisttable ).on('single_double_click', 'tr', fn) // shold be
$('#packagelisttable').on('single_double_click', 'tr', fn)
$(document).on('single_double_click', 'packagelisttable tr', fn) // should be
$(document).on('single_double_click', '#packagelisttable tr', fn)

Correct syntax for defining an event delegator

Normally you write a handler for a button click like this:
$(document).ready(function()
{
$("button").click(function()
{
doSomething();
});
});
But in the case of an event delegator, to respond to an event with a function such as this:
function doSomething(event)
{
if (ev.target.id == 'button1' )
{
//do your stuff
console.log('#button1 click');
}
else
{
console.log('not a #button1 click');
}
}
What I'm confused about is the correct syntax for defining the event that calls this delegator function - this? (A):
$(document).ready(function()
{
$(function()
{
$('button').click(doSomething);
});
});
or this? (B):
$(document).ready(function()
{
$("button").click(doSomething);
});
Which is correct and why?
In choice A you are just repeating the document.ready syntax twice.
// These two lines are equal
$(document).ready(fn);
$(fn);
All you need to do is choice B
While choice B would certainly be the way to do this if you needed to use a separate function, i.e., in the case where you needed to invoke the function from somewhere other than a button click, my preference is usually to put the code in line. The only other times I don't do this is when it would improve readability.
$(function() {
$("button").click( function(e) {
if (e.target.id == 'button1') {
alert('button1 clicked');
}
...
});
});

Categories