Given some simple HTML such this, where one element has an onclick function and it's child also has an onclick function:
<div style='background-color:blue;width:500px;height:500px;'
onclick='thing1();'>
<div style='background-color:red;width:100px;height:100px;'
onclick='thing2(57);'></div>
</div>
What would be the correct approach so that when a user clicks the child element, only the child's onclick is executed and not the parent's, but when the parent is clicked, it's onclick is still executed? I see that event.stopPropagation() would be the correct way to go, but since I'm passing an argument to the function thing2(), I can't seem to pass the event as well. For example:
function thing2(a,ev) {
// Do something with a
ev.stopPropagation();
}
Doesn't work, failing with the error TypeError: ev is undefined.
JQuery is fine.
The event is the first param.
function thing2(ev) {
var a = ev.target
ev.stopPropagation()
}
Secondly, it's best not to use onclick=. Instead, give your div classes or ids and do something like this:
<div class="thing-1" data-thingy="57">
<div class="thing-2" data-thingy="65"></div>
</div>
<script>
$('.thing-1').click(function (ev) {
ev.stopPropagation()
parseInt($(ev.target).data('thingy'), 10) // 57
})
$('.thing-2').click(function (ev) {
ev.stopPropagation()
parseInt($(ev.target).data('thingy'), 10) // 65
})
</script>
When you call a function on click, no event will be passed as argument and it somehow you can do that, that is not a Jquery object and that will not have stopPropagation property. SO you need to define jQuery click event handler for both divs, let's give them ids div1 and div2.
HTML
<div id="div1" style='background-color:blue;width:500px;height:500px;'>
<div id="div2" style='background-color:red;width:100px;height:100px;'></div>
</div>
In Javascript,
function thing2(ev) {
// Do something with a
console.log(ev);
alert('hi2');
ev.stopPropagation();
}
function thing1(ev) {
// Do something with a
alert('hi1');
}
$('#div1').click(thing1);
$('#div2').click(thing2);
Related
I'm trying to rewrite my functional code to module pattern js, and I have this issue - When I try to delete input field which is dynamically created, I use jQuery $(this) to access dom element and delete its parent 'div'. But this refers to the Modal object, not the component I clicked. How to solve it, without making some field counter and creating fields with unique ID's, then catching ids on click and deleting that input field?
My modal:
var s,
Modal = {
settings: {
addInputBtn: $("#add-input"),
inputContainer: $("#modal-input-form"),
checkBoxesList: $(".check-box"),
inputFieldsList: $(".form-control"),
inputFieldsOptionalList: $(".optional-modal"),
inputHtml: `
<div class="input-group mb-3 optional-modal">
<div class="input-group-prepend">
<div class="input-group-text">
<input type="checkbox" class="check-box">
</div>
</div>
<input type="text" class="form-control">
<button type="button" class="close">
<span>×</span>
</button>
</div>`
},
init: function () {
s = this.settings;
this.bindUIActions();
},
bindUIActions: function () {
s.addInputBtn.on("click", () => Modal.addInput());
s.inputContainer.on("click", ".close", () => Modal.deleteInput());
},
addInput: function () {
s.inputContainer.append(s.inputHtml);
},
deleteInput: function () {);
$(this).parent('div').remove();
}
}
Modal.init();
deleteInput: function (e) {);
$(e.target).parent('div').remove();
}
Event handlers are passed an event argument. Among its useful properties is target, which is the html element that the event originated on. Note that it could be different from the this of the event handler, which is the element that the event handler is attached to, as events bubble up through the DOM. So if you have this html:
<div id="parent">
<div id="child"></div>
</div>
then for this JS function:
$("#parent").on('click', function(e){
//this will equal <div id="parent"> unless you bind the handler to something else
//e.target will equal the clicked element:
//if the user clicked the child, it will equal the child;
//if the user clicked parent directly, it will equal parent.
$(e.target).closest('#parent').doSomething();
});
Did you try with:
deleteInput: function () {;
$(this.settings).parent('div').remove();
}
Also you have a typo at deleteInput: function () { ); ... the rest of the code, delete that extra ) after function. I suggest you trying $(this.settings).. because, this gets the Modal, and then you need to access the other object inside that object, which is settings. So your modal object, consists of other object, and I'm thinking this way you should be able to get it :)
I am trying to trigger a custom event in a parent element from the child elements event. The parent element is HelpMenuHeader and it's custom event is defined in HTML as "onsubmenu_click".
Here's a snippet of the HTML that just shows one menu tree.
<span class="formMenu" id="HelpMenuHeader" onsubmenu_click="OnMenuClick()">Help
<div class="formMenu" id="HelpAbout" onmouseup="MenuChildClick()">About us...</div>
</span>
In the child element, HelpAbout, the MenuChildClick event needs to trigger the parent's onsubmenu_click event so that that will execute (that event handler uses the parent's information).
Here's a snippet of the javascript I have for MenuChildClick:
function MenuChildClick()
{
var srcElement = this.event.srcElement;
if (srcElement.id != "spacer" && srcElement.tagName != "HR")
{
// NONE OF THE LINES BELOW WORK
//parent.$(srcElement).trigger('onsubmenu_click');
//$(srcElement).trigger('onsubmenu_click');
//var event = document.createEvent('Event');
//event.initEvent('submenu_click', true, true, null);
//srcElement.dispatchEvent(event);
//oEvent = createEventObject();
//oEvent.result = srcElement.id;
//onsubmenu_click.fire(oEvent);
}
}
I'm having a problem getting a reference to the correct parent element in the MenuChildClick event because when I check the parent reference doesn't have the parent ID.
And then once I have the correct parent reference I need to execute the parent's onsubmenu_click custom event. (The parent event is already being listened to since it's defined in the HTML, right?)
I have to support IE compatibility view so I need it to work for previous IE versions as well.
Anyone tell me how I can do these things (1 & 2 above) leaving the HTML as it is?
Thanks in advance.
You can use jQuery methods .on() and .trigger() instead of event handler attribute
$(function() {
function parentHandler(event, args) {
console.log(event.type, args)
}
$("#HelpMenuHeader").on("submenu_click", parentHandler);
$("#HelpAbout").on("mouseup", function() {
$(this).parent().trigger("submenu_click"
, ["triggered from #" + this.id])
})
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<span class="formMenu" id="HelpMenuHeader">Help
<div class="formMenu" id="HelpAbout">About us...</div>
</span>
First you have to pass the element that is triggering the event in your HTML by changing your HTML to this:
<span class="formMenu" id="HelpMenuHeader" onsubmenu_click="OnMenuClick()">Help
<div class="formMenu" id="HelpAbout" onmouseup="MenuChildClick(this); return false;">About us...</div>
</span>
Notice that I pass the element that is triggering the function call by passing 'this' through the onmouseup function call.
Then you can use the passed element to define which elements you want to monitor as follows:
function MenuChildClick(element)
{
var srcElement = element;
var parent = element.parentNode
if (srcElement.id != "spacer" && srcElement.tagName != "HR")
{
//parent.trigger('onsubmenu_click');
}
}
I'm trying to detect with jQuery's on only events that are not namespaced.
I tried checking the namespace within the callback of on as follows, but it's always undefined:
$(".selector").on(
"click",
function (e) {
console.log(e.namespace); // Undefined, not "mynamespace"
}
);
$(".selector").trigger("click.mynamespace");
I've also read that you can append ".$" to the event name to rule out any namespaces, but that only seems to apply within trigger, not within on. The following runs even if the event is namespaced:
$(".selector").on(
"click.$",
function (e) {
// runs even when triggered with a namespace
}
);
I'm not sure where to go from here since when I log the event object, the namespace is nowhere to be found.
Thanks in advance!
Try to access it through handleObj.
HTML:
<div class="selector">
BOX
</div>
<button onclick="clickWithNamespace()">with ns</button>
<button onclick="clickWithoutNamespace()">without ns</button>
JS:
$(".selector").on(
"click.mynamespace",
manageClick
);
$(".selector").on(
"click",
manageClick
);
function manageClick(event) {
console.log(event.handleObj.namespace);
$(".selector").text(event.handleObj.namespace);
}
function clickWithNamespace() {
$(".selector").trigger("click.mynamespace");
}
function clickWithoutNamespace() {
$(".selector").trigger("click");
}
https://jsfiddle.net/j52rmxrs/15/
This is my markup:
<div id="divContainer">
<div>
<table></table>
</div>
<div>
<table></table>
</div>
....
</div>
I need to to register mouseenter event on all tds of all the tables (that are present inside each div).
$(document).ready(function () {
$allTds = $('#divContainer').find("tr").find("td");
...
SomeFunction();
});
function SomeFunction(){
$allTds.on({
mouseenter: function (e) {
alert('hover');
}
});
}
But I don't get any alerts.
They way you apply the event listener is weird.
$('#divContainer').on('mouseenter','td',function() {
alert('mouse entered');
});
Also: It's good that you cache the td elements, but why don't you stick with something more simple?
$allTd = $('#divContainer td');
The reason your event handlers aren't being bound is that the <td> elements don't exist when you enter the document ready handler.
You should use event delegation for this. For example
window.jQuery(function($) {
$('#divContainer').on({
mouseenter: function(e) {
alert('hover');
}
}, 'td');
});
This way, it's the #divContainer element that listens for the events and acts on them if they originate from a <td>.
See http://api.jquery.com/on/#direct-and-delegated-events
You also had a scoping problem where the $allTds variable is only defined in the document ready handler and is not in scope of the SomeFunction function.
I have a nested div like this
<div id="one">
<div id="two">
id two goes here
</div>
<div id="three">
id three goes here
</div>
<div id="four">
id four goes here
</div>
</div>
Now i want to handle click and doubleclick events on all divs except in div#four,
like this
$('#one').live('dblclick', function() {
my javascript code goes here
});
('#one').live('click', function() {
my javascript code goes here
});
How can i use the above script and exclude the last nested div #four.
Thanks
Like this:
$('#one, #one > div').not('#four').delegate('dblclick, click', function(){
// my javascript code goes here
});
EDIT: Based on further clarification, try this:
$('#one').bind('click dblclick', function( event ) {
var id = event.target.id;
if(id == "one" || id == "two" || id == "three") {
if(event.type == "click") {
// code for click event
} else {
// code for double click event
}
}
});
EDIT: Based on our conversation under another answer, it seems like you want the #one element to be clickable, but none of its child elements. If that is right, try this:
$('#one').click(function() {
// code to run when `one` is clicked.
}).children().click(function( event ) {
event.stopPropagation();
});
Now if there's any text in #one, the code for that element will fire, but it will not fire when you click any children of #one.
Let me know if that was what you wanted.
EDIT:
If you are saying that you will have a dynamic number of elements inside #one, and the last one will not get the event, then do this:
$('#one').delegate('div:not(:last-child)', 'click dblclick', function( event ) {
if(event.type == 'click') {
// do something for the click event
} else {
// do something for the double click event
}
});
Note that this assumes there will not be nested divs. Results may be unexpected if there are. Also, the #one element doesn't fire events. Only its children.
Original answer:
$('#one,#two,#three').bind('click', function(){
// code for click event
})
.bind('dblclick', function() {
// code for double click event
});
Or replace .bind with .live if you really need it.
I would use an additional class:
HTML:
<div id="one">
<div id="two" class="clickable">
id two goes here
</div>
<div id="three" class="clickable">
id three goes here
</div>
<div id="four">
id four goes here
</div>
</div>
JS:
('.clickable').live('click', function() {
});
Use not method, more on this here: How can I exclude these elements from a jQuery selection?
You must use $('#one') instead $('.one') aren't you?
$("div:not(#four)")
or
$("#one :not(#four)")
Will select any div that does not have the id="four" set. Basically the :not is what you are looking for. Anything in the :not parenthesis is negated for selection purposes.
http://api.jquery.com/not-selector/
An alternative is to attach a single click/double click handler to the parent which means no need for .live or anything, and in the handler ensure that you are receiving a click from an acceptable child with $(event.target).is(":not(#id)")
$("#one").click(function(event) {
if (this != event.target && $(event.target).is(':not(#four)')) {
// do work on event.target
}
});
// ...