Propagation of custom events - javascript

I expect my CustomEvent to be propagated from document to all the DOM elements.
For some reason, it does not happen. What am I doing wrong?
<html>
<script>
function onLoad() {
var myDiv = document.getElementById("myDiv");
myDiv.addEventListener("myEvent",function(){alert("Yes!");});
document.dispatchEvent(new CustomEvent("myEvent",{detail:null}));
}
</script>
<body onload="onLoad()">
<div id="myDiv"></div>
</body>
</html>

By default Custom Events are not bubbled.
Reason being, Custom Event definition says:
let event = new CustomEvent(type,[,options]).
Options have a flag : bubbles, which is false by default, we have to enable it.
Following will fix your code
<html>
<script>
function onLoad() {
var myDiv = document.getElementById("myDiv");
myDiv.addEventListener("myEvent",function(){alert("Yes!");});
document.dispatchEvent(new CustomEvent("myEvent",{detail:null,bubbles:true}));
}
</script>
<body onload="onLoad()">
<div id="myDiv"></div>
</body>
</html>

You have to dispatchEvent the event on the element you want the event 'triggered' on. It will then propagate down and back up the DOM
<html>
<script>
function onLoad() {
var myDiv = document.getElementById("myDiv");
myDiv.addEventListener("myEvent",function(){alert("Yes!");});
myDiv.dispatchEvent(new CustomEvent("myEvent",{detail:null}));
}
</script>
<body onload="onLoad()">
<div id="myDiv"></div>
</body>
</html>
fiddle: https://jsfiddle.net/yrf9cvr3/
How propagation works: The event starts at the document and works it's way down to the element it was dispatched on (You can capture the event going this way using onCapture flag). Then goes back up to the document. Because you are dispatching on the document the event doesn't really go anywhere, only document see the event.

This is currently not possible as stated in the MDN doc https://developer.mozilla.org/en-US/docs/Web/Events/Creating_and_triggering_events#event_bubbling, event can only bubble from child to ancestors, i.e. upward for now.
The best way you can achieve this is use document.querySelector to target the element(s) you want to dispatch the event to, then dispatch as needed.
document.querySelector("#myDiv").dispatchEvent(customEv);

Try this one. Use document.querySelector and specify the events you want to track. Click the button or type some text in the text box
<html>
<script>
function onLoad() {
// var myDiv = document.getElementById("myDiv");
// myDiv.addEventListener("myEvent",function(){alert("Yes!");});
// document.dispatchEvent(new CustomEvent("myEvent",{detail:null}));
var myDiv = document.querySelector("#myDiv");
myDiv.addEventListener("click", myEventHandler, false);
myDiv.addEventListener("change", myEventHandler, false);
}
function myEventHandler(e)
{
alert('Element was '+e.target.id+'\nEvent was '+e.type);
}
</script>
<body onload="onLoad()">
<div id="myDiv">
<input type="button" id= "Button 1" value="Button 1"><br>
<input type="text" id="Text 2">
</div>
</body>
</html>

I am posting some solution, not really an answer.
This will propagate a custom event to all the elements in the DOM.
<html>
<script>
document.dispatchCustomEvent = function(event) {
function visit(elem,event) {
elem.dispatchEvent(event);
var child = elem.firstChild;
while(child) {
if(child.nodeType==1) visit(child,event);
child = child.nextSibling;
}
}
visit(document.documentElement,event);
}
function onLoad() {
var myDiv = document.getElementById("myDiv");
myDiv.addEventListener("myEvent",function(){alert("Yes!");});
document.dispatchCustomEvent(new CustomEvent("myEvent",{detail:null}));
}
</script>
<body onload="onLoad()">
<div id="myDiv"></div>
</body>
</html>

Going with the extreme. Events propagate down to the element they are dispatched on and back up... So in order to trigger an event on any and essentially all elements (since it is unknown which elements need the event) you can find the "ends" of all of the "branches" of the DOM and dispatch events to them.
jQuery makes it easy to select the end of the branches
function onLoad() {
var myDiv = document.getElementById("myDiv");
myDiv.addEventListener("myEvent", function() {
alert("Yes!");
});
$(':not(:has(*))').each(function(i, el){
el.dispatchEvent(new CustomEvent("myEvent", {
detail: null,
bubbles: true
}));
});
}
https://jsfiddle.net/dkqagnph/1/
Using this will ensure EVERY DOM element (attached to the body) gets the event (assuming that no element stop propagation itself) and thus making there be no need to know which elements are listening or care about the event. This doesn't dispatch to every individual element, as that would be overkill, but just the end and lets bubbling do it's thing.
NOTE: elements with more than one child will get the event more than one time. You may want to have a way to ensure that your code does run more than once or does not care if it runs more than once.

Related

javascript to auto click a link not working

hello im trying to get a script to run so that a link auto clicks after certain amount of time
on familyoffices.com the link is the "we are online" graphic at the bottom right
im using
<script type="text/javascript">
$(document).ready(function() {
setTimeout(function() {
$('#desginstudio-button-image-desktop').click();
}, 300);
});
</script>
unfortunately this isn't firing off....anyone know how i can achieve this?
Try using
<head>
<script>
function haveclicked(){
document.getElementById('myLink').click();
}
</head>
<body onload="setTimeout('haveclicked();',3000);">
<a id="myLink" href="http://www.google.com" target="_blank">GOOGLE</a>
</body>
Consider this from the MDN.. You need to create an event to do this correctly.
function simulateClick() {
var evt = new MouseEvent("click", {
bubbles: true,
cancelable: true,
view: window
});
var cb = document.getElementById("checkbox"); //element to click on
var canceled = !cb.dispatchEvent(evt);
if(canceled) {
// A handler called preventDefault
alert("canceled");
} else {
// None of the handlers called preventDefault
alert("not canceled");
}
}
document.getElementById("button").addEventListener('click', simulateClick);
<p><label><input type="checkbox" id="checkbox"> Checked</label>
<p><button id="button">Click me</button>
Instead of
$('#desginstudio-button-image-desktop').click();
Try using
$('#desginstudio-button-image-desktop').trigger('click');
You can try to first locate the iframe and the element in it --
var frame = document.getElementById(/* your frame id*/),
button = frame.contentDocument.getElementById(/* your button id*/);
Then dispatch a synthetic event --
button.dispatchEvent(new MouseEvent("click", { bubbles: true }));
Some browsers/versions don't support using click() to trigger a click event. Try using .trigger('click') instead

How can I remove every listener from a page?

I know how to remove a listener from an element, but how can I remove every event listener from every element on the page?
A jQuery and pure JS solution would be nice.
I would suggest to look into the .off function of jQuery.
Also, based on this stackoverflow question, I would try to remove all every listeners with the following code
$("body").find("*").off();
Hope this could help you.
You can try this too.
http://jsfiddle.net/LkfLezgd/9/
$("#cloneButton").click(function() {
$('body').replaceWith($('body').clone().html());
});
You can loop through the form elements as below to remove the event listeners at your preferred way.
The fastest way to do this is to just clone the node which will remove all event listeners but this won't remove if 'onclick' attribute is used.
document.getElementById('button').addEventListener('click', onClick, false);
function onClick() {
console.log('Form clicked');
var form = document.getElementById('myForm');
for(var i = 0; i < form.elements.length; i++){
var elm = form.elements[i];
removeEvents(elm);
}
}
function removeEvents(elm) {
// The fastest way to do this is to just clone the node, which will remove all event listeners:
var new_element = elm.cloneNode(true);
elm.parentNode.replaceChild(new_element, elm);
}
<form id="myForm">
<input id="button" type="button" value="Click" />
</form>
Just Clone the HTML dom, that will remove the events by default.
Here is an example.
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
<script>
$(document).ready(function () {
$("#EventButton").click(function () {
alert("Click event worked");
var old_element = document.documentElement;
var new_element = old_element.cloneNode(true);
old_element.parentNode.replaceChild(new_element, old_element);
});
});
</script>
</head>
<body>
<button id="EventButton">Remove Events</button>
</body>
</html>

How to trigger MouseDown via PhantomJS?

I tried:
var clickEvent = document.createEvent('MouseEvents');
clickEvent.initEvent("mousedown", true, true);
jQuery('.left-rail-facets .facet-list .facet.CS .suggestion[data-value="B"] a')[0].dispatchEvent(clickEvent);
but it just fails to trigger the action on the site.
no error returned.
This is how you programmatically trigger a click on a DOM element with a "mousedown" event. To answer your question, you need to have two things in your source code:
event listeners to detect the clicks
and
commas between your multiple selectors in your jQuery line.
Please run the snippet below, which shows the modified jQuery line and the listeners running correctly.
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
// You must have event listeners to see if anything is actually happening. For example, here I will add only a listener to the first element:
jQuery(".left-rail-facets")[0].addEventListener('mousedown', function(e) {
jQuery(".left-rail-facets")[0].innerHTML = "I have received a click.";
}, false);
// Now here is the code from your question. Please see how I have commas instead of spaces in my jQuery selector:
var clickEvent = document.createEvent('MouseEvents');
clickEvent.initEvent('mousedown', true, true);
jQuery('.left-rail-facets,.facet-list,.facet.CS,.suggestion[data-value="B"],a')[0].dispatchEvent(clickEvent);
});
</script>
</head>
<body>
<h1>I am a Webpage</h1>
<p class="left-rail-facets">I have not received a click.</p>
<p class="facet-list">I have not received a click.</p>
<facet class="CS">I have not received a click.</facet>
<p class="suggestion" data-value="B">I have not received a click.</p>
I have not received a click.
</body>
</html>
You will need to use the document.createEvent and event.initMouseEvent:
var element = document.querySelector('.left-rail-facets .facet-list .facet.CS .suggestion[data-value="B"] a');
//or var element = jQuery('.left-rail-facets .facet-list .facet.CS .suggestion[data-value="B"] a')[0];
var elementRect = element.getBoundingClientRect();
var mouseEvent = document.createEvent('MouseEvents');
mouseEvent.initMouseEvent('mousedown', true, true, window, 0, elementRect.left, elementRect.top);

Get id of a span in JavaScript.

I want to get the span id in JavaScript following code always returning M26 but I want different values on different click M26 or M27:
function clickHandler() {
var xid= document.getElementsByTagName("span");
var xsp= xid[0].id;
alert(xsp);
}
}
<html>
<BODY LANGUAGE = "javascript" onClick = "clickHandler();">
<a href="javascript:void(0)"><u><b><span id=M26>2011-
2012</span></b></u></a>
<div id=c26 STYLE="display:none">
<a href="javascript:void(0)"><u><b><span id=M27>2012-
2013</span></b></u></a>
<div id=c27 STYLE="display:none">
</body>
</html>
The problem you are facing is that var xid= document.getElementsByTagName("span"); gets all spans on the page regardless of where you click.
To solve this problem you should just pass a reference to the clicked object within the function. For example:
<span id=M26 onclick="clickHandler(this);" >2011-2012</span>
Then in your javascript code:
function clickHandler(object) {
alert(object.id);
}
However it is a good idea to bind the events within javascript rather than inline in the html tags.
This article describes the different ways in which you can bind events to elements.
There are several ways to get the id of the element that has just been clicked:
Pass a reference to this to the handler:
onclick="handlerFunc(this);">
Or, better yet, pass the event object to the handler, this allows you to manipulate the event's behaviour, too:
onclick='handlerFunc(event);'>
//in JS:
function handlerFunc(e)
{
e = e || window.event;
var element = e.target || e.srcElement;
element.id;//<-- the target/source of the event (ie the element that was clicked)
if (e.preventDefault)
{//a couple of methods to manipulate the event
e.preventDefault();
e.stopPropagation();
}
e.returnValue = false;
e.cancelBubble = true;
}
You can use getAttribute() function for this...
function clickHandler() {
var xid= document.getElementsByTagName("span");
var xsp= xid[0].getAttribute('id');
alert(xsp);
}
<html>
<body LANGUAGE = "javascript" onload = "clickHandler();">
<a href="javascript:void(0)"><u><b><span id=M26>2011-
2012</span></b></u></a>
<div id=c26 STYLE="display:none">
<a href="javascript:void(0)"><u><b><span id=M27>2012-
2013</span></b></u></a>
<div id=c27 STYLE="display:none">
</body>
</html>
See working Demo

Javascript Dynamic Event Handling, Not Jquery

here is my code
<html>
<head>
<script type="text/javascript">
window.onload = function(){
sel = document.getElementsByTagName('select');
for(i=0;i<sel.length;i++)sel[i].onclick = function(){alert('');}
}
</script>
</head>
<body>
<div id="ss"></div>
<select></select>
<input type="button" onclick="document.getElementById('ss').appendChild(document.createElement('select'))"/>
</body>
</html>
"onclick" event working for static tag "Select" but not working for Dynamically created "Select". In other word i want to know what is alternate to .live of JQuery in Javascript.
Bind the event to a parent element, that already exists in the DOM:
document.body.addEventListener('click', function (e) {
if (e.target.tagName.toLowerCase() == 'select') {
alert('You clicked a select!');
}
});
JS Fiddle demo.
It would be slightly more sensible to bind the click to an element 'closer' to the form, and if you use getElementById() rather than getElementByTagName() it's more simple, since you don't have to worry about the index of the number you're binding to.
jQuery's live function works by using "Event Delegation". The basic idea is that you bind a listener on a parent element, which is guaranteed to exist when the page loads. Any element below that (with the exception of some) will fire off an event which can be caught by the parent listener. From there you would need to retrieve the target/sourceElement of the event and determine whether or not it's one you care about.
Something like this will work for listening to clicks. Just make sure that any new elements you are adding are located within the proper parent container and have an attribute which distinguishes them from the rest of the clickable elements.
<html>
<head>
<script type="text/javascript">
window.onload = function(){
// get the relevant container
var eventContainer = document.getElementById("EventContainer");
// bind a click listener to that container
eventContainer.onclick = function(e){
// get the event
e = e || window.event;
// get the target
var target = e.target || e.srcElement;
// should we listen to the click on this element?
if(target.getAttribute("rel") == 'click-listen')
{
alert("You clicked something you are listening to!");
}// if
};
};
</script>
</head>
<body>
<div id="EventContainer">
<input type="button" rel="click-listen" name="myButton" value="Listening to this button." />
<input type="button" name="anotherButton" value="Not listening." />
<p>I'm also listening to this a element: listening to this</p>
</div>
</body>
</html>
there's no need to bind the onclick handler to every select every time you add one.
I am not going to retype your whole page, but you'll see what's going on by reading following snippets:
function handler() {
alert('You clicked a select!');
}
window.onload = function(){
sel = document.getElementsByTagName('select');
for(int i= 0; i < sel.length; i++) {
sel[i].onclick = handler;
}
}
function addSelect() {
var slt = document.createElement("select");
document.getElementById('ss').appendChild(slt);
slt.onclick = handler;
}
<input type="button" onclick="addSelect();"/>
You're only setting the onclick when the window loads. All you need to do is put the code currently in the window.onload into a named function, then call it every time you add a new select.
here's the dumb way to do it:
<html>
<head>
<script type="text/javascript">
function update () {
sel = document.getElementsByTagName('select');
for(i=0;i<sel.length;i++)sel[i].onclick = function(){alert('');}
}
window.onload = update;
</script>
</head>
<body>
<div id="ss"></div>
<select></select>
<input type="button" onclick="document.getElementById('ss').appendChild(document.createElement('select'));update();"/>
</body>
</html>
You can use a cross-browser solution as shown below to add event handler dynamically
sel = document.getElementsByTagName('select');
for( i=0; i<sel.length; i++){
if (sel[i].addEventListener){
sel[i].addEventListener("click", clickHandler, false);
} else if (sel[i].attachEvent){
sel[i].attachEvent("onclick", clickHandler);
}else{
sel[i].onclick = clickHandler;
}
}
function clickHandler(event){
}

Categories