Javascript - trigger custom parent html event from child element - javascript

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');
}
}

Related

Run Child's Onclick But Not Parent's Where Argument is Passed

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);

JS event listener for a type of element?

Is there a way to add some kind of listener for a type of html element? For example if i wanna call a function when the user clicks any p element
the easiest answer would be using addEventListener() if you want a specific html tag just like what i wanted in my question then you'll find the answer there ill paraphrase it here too
add this
<script>
document.addEventListener("click", function(e){
//your desired nodeName like : DIV , SPAN , LI etc
if(e.target && e.target.nodeName== 'DIV')
//add a function below to trigger
{alert('bingo')}
});
</script>
to the end of your document
by the way don't forget to use uppercase nodeNames or just put a toLowerCase() before it. cheers :)
Add the event listener to the window / document / document.body and check the type of the element and the types of its parents because if you have a <span> inside a <p>, clicking the span won't trigger the click in the paragraph.
document.addEventListener("click", function (eventArgs) {
var target = eventArgs.target;
var elementToLookFor = "p";
while (target !== null) {
if (target.tagName.toLowerCase() === elementToLookFor) {
// Do magic stuff with the paragraph
console.log(target);
}
target = target.parentElement;
}
});
This technique is called "event delegation."
Edit: Note that you cannot early return from the loop above. If your have nested paragraphs, i.e.
<p>
Hey,
<p>there!</p>
</p>
Having an early return will only call your event handler for the inner paragraph, whereas you said that you'd like the handler to be invoked on every paragraph which is why you need to traverse all the ancestors of the element.
I assume that you are looking for code along these lines:
var paras = document.getElementsByTagName("p");
// Loop through elements.
for(var i = 0; i < paras.length; i++) {
// Add listener.
paras[i].addEventListener("click",
function() {
// Execute function.
}, false);
}
I'd just select all the elements on the page and add eventListeners on them like so:
function addListeners(elementType, eventType, callback) {
Array.prototype.slice.call(document.querySelectorAll(elementType)).forEach(function (el, i) {
el.addEventListener(eventType, callback, false);
});
}
Above we use querySelectorAll to pick all the wanted elements, convert it to an Array (if you use es6, you can use Array.from) and then we loop through the array and add listeners with the wanted callback.
Here's an example: https://jsfiddle.net/a7en4d4s/
Look at this JSFiddle, and see if it works for you
<span>Click Yes</span><br/><br/>
<span>Click No</span><br/><br/>
<a>Clicked: <b id="result"></b></a>
<script>
$("span").click(function(){
var a = $(this).html();
$("#result").html(a);
});
</script>

passing event data dynamically in jquery

Please refer below HTML
<div class="Icon">
<span>
<img src=""/>
</span>
</div>
I am adding class "bootstrap-modal" dynamically to above IMG tag when it is clicked.
$(".Icon img").on("click", function (e) {
var data="some object";
$(this).addClass("bootstrap-modal");
});
Then i have one more click event for bootstrap-modal class like below
$(document).on('click',"bootstrap-modal" function (e,data) {
//here i need to get data object
});
how to pass data object from img click event to bootstrap-modal click event?
That means I need to get some values from previous click handler ?
How can I do this ?
Save it in data:
$('.Icon img').on('click', function(e) {
var data = 'some object';
$(this).addClass("bootstrap-modal").data('test', data);
});
$('.Icon').on('click', '.bootstrap-modal', function(e, data) {
var data = $(this).data('test');
});
FYI: Since you use the newest version of jQuery, you'd better use on method with event delegation instead of deprecated live. Here .Icon is supposed to be a static parent element of .bootstrap-modal.

JavaScript delegate for elements with child nodes

In a simple example, I try to make delegate for first-level children of an element. The problem comes when the child elements have children. The mouse event consider the clicked element (regardless of level).
My solution is to cycle until reaching the first-level child; but I wonder if this is the best method to do so.
Isn't there a method for directly returning the first-level children upon delegate click?
JS
window.onload=function(){
document.getElementById('test').addEventListener('click', function(e){
console.log(e.target);alert(e.target.id);
}, false);
}
HTML
<div id="test">
First
<b>Second</b>
Third
Fourth
<div id="div">Division</div>
<div id="div2"><span>Division</span></div>
</div>
If it's only the first level elements you're after, you could check if the parentNode of the clicked element is the root, no further traversing needed. Otherwise you'll need to traverse up to the first child of the root. Something like:
// level0 is the root
level0.addEventListener('click', function(e) {
var from = e.target || e.srcElement;
from = from.parentNode === level0 ? from : findFirst(level0,from);
/** do things **/
}, false);
// traverse up to first child of [root]
function findFirst(root,el){
while(true){
el = el.parentNode;
if (el && el.parentNode === root){
return el;
}
}
return null;
}
Here is a fork of your jsfiddle, using the above.
using only javascript you can use a recursive function that will find the first parent element with an id:
function findParentWithId(element){
if(element.id){
return element;
}
return findParentWithId(element.parentNode);
}
​and then, use it with the target element of the event
document.getElementById('test').addEventListener('click', function(e){
console.log(findParentWithId(e.target));alert(findParentWithId(e.target).id);
}, false);
I'm not sure what's beeing ask here. Events do Bubble by default (which is actually not true, by default they would traverse top->down) because its most common to call .addEventListener with false as third argument.
You can stop most events from further bubbling up, by calling eventObject.stopPropagation() on the node where you want to stop it.
If you want to "prefilter" only the first-level children, you shouldn't use delegation at all, but query with .querySelectorAll like
[].forEach.call( document.querySelectorAll('#test > *'), function( node ) {
node.addEventListener('click', function( event ) {
alert( this.id );
}, false);
});
That would bind click event listeners on all direct children from #test.
See that in action: http://jsfiddle.net/8Xmn4/
Getting a reference to all first level children of a node is simple:
window.onload=function(){
document.getElementById('test').addEventListener('click', function(e){
return document.getElementById('test').children;
}, false);
}
this outputs, on Firebug format:
[a#first #, a#second #, a#third #, a#fourth #, div#div, div#div]
Obviously, it returns the children with their respective children, but the first level reference remains.
jQuery(':first-child') use this jquery to get the first child

Which HTML element was Double Clicked in the DOM

I would like to detect which HTML element was double clicked. Seems to something not fire in my code. Following is my HTML code structure where you double click detect which item is clicked.
<div id="mainWrapper">
<div id="Banner" name="Banner" class="editable">This is the banner</div>
<div id="MainMenu" class="editable">This is the main menu</div>
<div id="LeftSideBar" class="editable">This is the submenu or left sidebar content</div>
<div id="MainContent"class="editable">Here is the main content</div>
<div id="RightSideBar" class="editable">Here are commercial ads</div>
<div id="Footer"class="editable">This is the footer
Go Home
</div>
</div>
External JavaScript
window.onload = function(){
// Listen to the double click event.
if ( window.addEventListener )
document.body.addEventListener( 'dblclick', onDoubleClick, false );
}
Get the element which fired the event. This is not necessarily the element to which the event has been attached.
function onDoubleClick( ev ){
var element = ev.target || ev.srcElement; //target = W3C, srcElement = Microsoft
alert(ev.type); //displays which event has fired
var targ;
if (!ev) var e = window.event;
if (ev.target) targ = ev.target;
else if (ev.srcElement) targ = ev.srcElement;
alert(ev.target); //displays which type of html element has been clicked (it shows div but not which div)
// Find out the div that holds this element.
var name;
do {
element = element.parentNode;
}
while ( element && ( name = element.nodeName.toLowerCase() ) && ( name != 'div' ||
element.className.indexOf( 'editable' ) == -1 ) && name != 'body' )
alert("The class name for the element is " + element.className); // I get nothing
alert("The node name for the html element is " + element.nodeName);// I get "body"
}
I'm not sure exactly what it is you're trying to accomplish. Is it so people can edit things? I'd be tempted to apply the onclick event listener just to those items you want to be editable. If they all have "editable" css classes, doing so is trivial with jquery:
$('.editable').dblclick(dblclickFunc)
This would apply an event listener to every element with a class of editable. However, to make it more useful, I'd change that to
$('.editable').dblclick(function(e){ dblclickFunc(e, this); })
and for the function
dblclickFunc(e, el){
alert('received an event of type ' + e.type + ' on ' + el.tagName);
}
So you've got a reference to the element that sent the event. From there, you could check IDs, or even go so far as to loop through all your editable elements and compare them to the one that got passed to you. Once you have a match, you know precisely which element was clicked on.
You are using JavaScript in your example, but you also tagged the question with jQuery, so I assume jQuery is OK to use. In fact, exactly this type of event handling is greatly simplified using jQuery’s API, since it normalizes the events for all modern browsers. Highly recommended.
You can delegate the event to the document and detect all double clicks in the entire document using jQuery using the on() function:
$(document).on('dblclick', function(e) {
console.log(e.target); // target is the element that triggered the event
alert("The class name for the element is " + e.target.className);
alert("The node name for the html element is " + e.target.nodeName);
});
If you want to listen on certain elements inside a specific container, try this:
$('#mainwrapper').on('dblclick', 'div', function(e) {
console.log(e.target);
});
This will listen for any double clicks inside #mainwrapper, but only trigger the handler if a DIV element was the target.
You can use .on()
$(".editable").on("dblclick", function(e){
$(this).attr('class') //Class Name
});

Categories