jQuery - stop propogation when selecting checkbox by input or td - javascript

I want to toggle a checkbox that is within a td by clicking the td itself (and / or the checkbox).
I have the following code:
$("[id^=musicCheckboxHoldingTD]").on("click", function (e) {
e.stopPropagation();
$this = $(this);
$this.find('.musicSelectionRoundCheckbox:checkbox').click();
});
$(".musicSelectionRoundCheckbox:checkbox").click(function(e) {
e.stopPropagation();
$this = $(this);
musicCheckboxToggled($this); // this function gets called twice
});
When I click only the td this works perfectly.
If I click the checkbox within the td then the function gets called twice due to an event for the td AND an event for the checkbox.
How do I prevent this happening to only have the function run once?
Thanks :-)

Do you really need two events ? From what i see, having just the event on the td without stoping the propagation would allow you to have an handler for your checkbox + td.
$("#musicCheckboxHoldingTD").on("click", function (e) {
musicCheckboxToggled($(this));
});
If your td have other thing that should not be triggering the event, you can tune the selector and prevent propagation.
$("#musicCheckboxHoldingTD, #musicCheckboxHoldingTD > input[type=checkbox]").on("click", function (e) {
e.stopPropagation();
musicCheckboxToggled($(this));
});

I had a lot of trouble with this and it seems that the browser was 'checking' the checkbox and then my jquery event was reversing that.
I ended up disabling the checkbox by putting disabled="disabled" in line with the HTML input element.
Then I used the following jQuery code:
$("[id^=musicCheckboxHoldingDiv]").on("click", function (event) {
event.stopPropagation(); // stop the event bubble up
$this = $(this);
var obj =$this.find('input');
obj.prop('checked', !obj.is(':checked'));
musicCheckboxToggled();
});
This is working at the moment. If anyone can see any issues with this answer then let me know in the comments or improve on it with another answer. I'll leave it a few days and then mark this as the accepted answer otherwise.
Thanks for everyones help :-)

Related

How to wrap multiple dynamic eventListeners into one?

I just started to learn js and need a little help: I have the following function:
//SET CHAT BEHAVIOR
function chatSettings() {
console.log('ChatSettings called')
function BtnAndScrollBar(texteditor) {
console.log('BTNAndScrollBar called');
const sendBtn = $('.cl.active').find('.sendBtn');
const attachBtn = $('.cl.active').find('.attachBtn');
console.log(sendBtn)
}
function sendAndDeleteMessage(send) {
console.log(send);
}
var sendBtn = $('.cl.active').find('.sendBtn');
sendBtn.mousedown(function () {
sendAndDeleteMessage(this);
});
var textEditor1 = $('.cl.active').find('.chatTextarea');
textEditor1.on('focus change mousedown mouseout keyup mouseup', function (){
console.log(this);
BtnAndScrollBar(this)
});
}
$('document').ready(function () {
console.log('hello');
$('.tabs').tabs();
chatSettings();
});
I prepared a js.fiddle - As you can see from console.log when clicking into the textarea, the eventListener always listens to #cl1, even if .cl.active switches along with the according TAB.
The events in the textarea are just relevant, if .cl is active. My target is to wrap all three eventListener into one and apply the event to the textarea in the active stream, but all I tried went wrong... Can anyone help? #Dontrepeatyourself #DRY
$(".chatTextarea").on(
'focus change mousedown mouseout keyup mouseup',
function (this) {
//this.id can contain the unique id
greatFunction(this);
});
This will bind event individually with unique id found with this keyword and also wraps all event listener into one function but this is better when you want to process each event with same functionality
please let me know if this helps.
Peace
$(".cl textarea").on('focus change mousedown mouseout keyup mouseup', function () {
greatFunction(this)
});
Tada!
P.S. Is there a reason greatFunction is defined inside window.onload?
Try using $(document).ready function to load code when the page loads.
Also use $('textarea #cl1').on to get the textarea with the #cl1 or whichever id you want to use and then call the function after using the .on.
Hope this helps!
Let me know if it works!
$(document).ready(function () {
function greatFunction(elem) {
//do stuff
}
$('textarea').on('focus change mousedown mouseout keyup mouseup', function () {
greatFunction(this)
});
}
First off, I changed the onload to bind with jQuery, so all your logic is doing jQuery bindings, rather than swapping back and forth between jQuery and vanilla javascript. Also, doing an actual binding removes an inline binding.
Next, the binding has been condensed into a single delegate event listener. Since you eluded in your comments that it wasn't working for the active element after the active was moved or added, this reflected that you were dealing with dynamic elements. Delegate event listeners are one way to handle such things.
Delegate event listeners bind on a parent element of the elements that will change, or be created. It then waits for an event to happen on one of it's children. When it gets an event it is listening for, it then checks to see if the element that it originated from matches the child selector (second argument) for the listener. If it does match, it will then process the event for the child element.
Lastly, I added some buttons to swap around the active class, so you could see in the snippet that the event handler will start working for any element that you make active, regardless of it starting out that way.
$(window).on('load', function () {
function greatFunction (elem) {
console.log(elem.value);
}
$(document.body).on(
'focus change mousedown mouseout keyup mouseup',
'.cl.active .chatTextarea',
function () {
greatFunction(this);
}
);
$('.makeActive').on('click', function () {
$('.active').removeClass('active');
$(this).closest('div').addClass('active');
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="cl1" class="cl active"><textarea class="chatTextarea">aa</textarea><button class="makeActive">Make Active</button></div>
<div id="cl2" class="cl"><textarea class="chatTextarea">bb</textarea><button class="makeActive">Make Active</button></div>
<div id="cl3" class="cl"><textarea class="chatTextarea">cc</textarea><button class="makeActive">Make Active</button></div>

Two OnClick events overlap, causing the first one to stop executing properly

I am trying to fit a new jQuery toggle function within an already working code. Basically, the toggle function should show/hide the below lying div form_fields_con with an onclick event.
The problem is that the form_fields_con div contains AJAX functionality triggered as well with an onclick event.
Toggle works when nothing in the form_fields_con div is changing but once clicked, the toggle function stops working.
This is the toggle function:
$(document).ready(function() {
$(".slidingDiv").hide();
$(".show_hide_search").show();
$('.show_hide_toggle').on('click', function(e) {
e.preventDefault();
var self = this,
sliding = $(this).closest('div').next('.slidingDiv').slideToggle(function() {
$($(self).children()[0]).text(function(_, txt) {
return txt == "–" ? "+" : "–";
});
});
});
});
And this is the AJAX one contained in form_fields_con div:
function selectcombobox(fuelcombobox, fuelid, fuelContainer, field_name) {
var popupvar = jQuery.noConflict();
popupvar('#'+fuelcombobox).css('display', 'none');
popupvar('#'+fuelid).css('display', 'block');
popupvar('#'+fuelContainer).css('display', 'none');
}
HTML and CSS posted in a JSFiddle here, to avoid too long post:
http://jsfiddle.net/Bradg/v8hzLt7f/1/
NOTE: For some reason I cannot simulate the error in JSFiddle, apologies for that.
How to prevent the two onclick functions' collision?
You change/recreate the DOM elements holding the onClick listener, a simple approach to get around your problem is event-delegation: http://api.jquery.com/on/ (see se second argument)
$('.slidingDiv').on('click', '.select_con_car', function() {
alert('clicked');
});
http://jsfiddle.net/5m2mwd9h/

JQuery - Clicking on checkbox container works, clicking on checkbox doesn't

I am trying to create a dropdown menu that will allow users to select multiple options via checkboxes. I am using jQuery so that the user just has to click within the checkbox container (i.e. the checkbox text or the whitespace around the text) to mark the checkbox as checked or unchecked, w/o solely having to click on the checkbox exclusively: http://jsfiddle.net/nMKt2/
<script type="text/javascript">
$(document).ready(function () {
$(".dropdown-menu li").click(function () {
var cb = $(this).find('input:checkbox');
var chk = cb.prop("checked");
if (!chk) {
cb.prop("checked", true);
}
else {
cb.removeProp("checked");
}
});
});
This works for the checkbox container, but it fails when you actually click on the checkbox itself! Actually clicking on the checkbox doesn't seem to trigger the toggle (you may have to open the jsfiddle in IE or Firefox to see this, as my version of Chrome didn't render this jsfiddle properly).
I am very new to jQuery/javascript, and so I'm sure I'm making an elementary mistake somewhere here. Another issue I don't know how to solve would be how to make the dropdown "sticky," so that it doesn't immediately disappear each time you check an option.
Any help you can offer would be greatly appreciated.
Here: http://jsfiddle.net/umidbek_karimov/y84ne/
1: Wrap Your input[checkbox] in to label:
<label><input type="checkbox" value="App1" />App1</label>
2: Use .stopPropagation() method on click event:
$(document).ready(function () {
$(".dropdown-menu li label").click(function (ev) {
ev.stopPropagation();
});
});
3: I also used display: block css property on labels
#advanced_options label {
font-weight:normal !important;
font-family: Tahoma, Geneva, sans-serif;
display:block;
cursor: pointer;
}
The click event on the checkbox is propagating up to the container so technically the checkbox will get checked, then unchecked right away (or vise versa). You need to stop the event propagation on the click event for the checkbox.
$('.dropdown-menu').on('click', 'input[type="checkbox"]', function(e) {
e.stopPropagation();
});
DEMO
$(document).ready(function(){
// Your code here.
$('.dropdown-menu li input:checkbox').on('click', function(e){
e.stopPropagation();
});
});
Your event attached to the <li> also affects all child elements. So what happens is when you click on the checkbox to check/uncheck it, the event attached to the <li> is triggered, causing it to essentially reverse the check/uncheck action.
To remedy this, we add e.stopPropagation(); to the checkbox to prevent it firing any parent click events.
As an alternative, you may want to consider a non-JavaScript solution, wrapping the contents of the list item in a label as shown below. When you click anywhere inside the label, browsers will natively trigger the check/uncheck action of a nested checkbox.
<li>
<label>
<input type="checkbox" value="...">
Checkbox
</label>
</li>
UPDATE:
Since there are other click events (from Bootstrap) that you want to preserve, what you really want to do is just abort out of the current click event when you click directly on the checkbox.
$(document).ready(function () {
$(".dropdown-menu li").on('click', function (e) {
// If you clicked on the checkbox directly, abort.
if ($(e.target).is('input'))
{
return;
}
var chk = $(this).find('input:checkbox').prop("checked");
if (!chk) $(this).find('input:checkbox').prop("checked", true);
else $(this).find('input:checkbox').removeProp("checked");
});
});

jQuery blur event fireing multiple times with dynamic content edit

When I click on a div element of a certain class, I change contenteditable to true. onblur of that clicked div I want it to alert something. The first time that I blur the div, it works fine, but after that it shows the same alert twice. So the first time, it alerts once. The second time, it alerts twice, etc.
What am I doing wrong?
content = $('#content');
content.delegate('div', 'click', function(event){
$(this).attr('contenteditable', 'true');
$(this).focus();
$(this).bind('blur', function(){
alert('blur');
});
});
Example: http://jsfiddle.net/W8que/4/
You're binding the blur again on each click. Each bind is new and they are stacking. Use .delegate() (or .on())for the blur function also.
fiddle: http://jsfiddle.net/W8que/11/
code:
content = $('#content');
content.on('click', 'div', function(){
$this = $(this);
$this.attr('contenteditable', 'true');
$this.focus();
});
content.on('blur', 'div', function(){
alert('blur');
});
Since the fiddle was already using jQuery 1.7.x, I went ahead and swapped out .delegate() for the more up-to-date .on(). Slipped in a few other things like caching $(this) and didn't bother passing the event into the function since there's nothing we need to preventDefault() or stopPropagation() on.
for prevent call multiple blur you can use 'off' before 'on'
for example :
$inputs.off().on("blur", function() {
})

jquery priority execution

Can anyone help me with this:
$('#n').click(function() {
$(this).parent().append(' delete');
$(this).next().click(function() {
alert('clicked'); //this not working
});
$(this).blur(function() {
$(this).next().remove();
});
});
JS Fiddle demo; the problem is that the blur() event is executed before click() event.
You can use a timeout to postpone the removal for some milliseconds.
example : http://jsfiddle.net/vkun9/7/
$(this).blur(function() {
var _this = this;
setTimeout(function(){$(_this).next().remove();},100);
});
I also moved the blur attaching to be outside of the click handler, as it was adding an additional one each time the element was clicked, and changed the click handler to the focus to avoid multiple remove buttons from repeated clicking on the input, as #dheerosaur noted.
so
$('#n')
.focus(function() {
$(this).parent().append(' delete');
$(this).next().click(function() {
alert('clicked'); //this not working
});
})
.blur(function() {
var _this = this;
setTimeout(function(){$(_this).next().remove();},100);
});
What you experience, though, is not a problem. It is the normal behaviour, as the element need to lose focus (fires the blur) before another element can have it.
You should also match the label for attribute with the id of the input element.
Use the outside events plugin and you can do something like this:
$('.input_field input').focus(function() {
var div = $(this).parent();
var link = $('delete').click(function(e) {
e.preventDefault();
alert('clicked');
}).appendTo(div);
$(this).data('delete', link);
}).bind('focusoutside clickoutside', function(e) {
var link = $(this).data('delete');
if (link && e.target != link[0]) {
link.remove();
}
});
First switch to using the focus event rather than the click event on your input field, some people actually use the keyboard to navigate through form fields ;-).
Then its creating the delete link, adding it to the page and storing a reference to it in on the input field.
Then with the outside event plugin we can bind focusoutside and clickoutside which get triggered when the user tabs or clicks outside the input field. By checking of the target of the event was the delete link or not we can tell if we should remove the link.
Example: http://jsfiddle.net/petersendidit/vkun9/6/
you can try setting a very short timeout in the blur event. this worked for me.
$(this).blur(function() {
setTimeout(function(){$(this).next().remove();}, 1);
});
Rather than using blur() I put together a hover()-based approach, though it does have a slightly clunky if/else statement:
$('.input_field').hover(
function(){
if ($(this).find('.delete').length) {
return false;
}
else {
$('delete')
.appendTo($(this));
}
},
function(){
if ($('#n').is(':focus')){
return false;
}
else {
$(this).find('.delete').remove();
}
}
);
JS Fiddle demo.
This approach does, however, ensure that there's only one delete link appended to the input_field (rather than the multiple links appended if the input is clicked multiple times in your original demo).

Categories