Custom Event having same name as native event - javascript

First of all, I would like to know whether it is right to create custom event with the same name as native event ?
My requirement is, I want to dispatch a custom event "click" with additional data using Javascript dispatchEvent. If I do so, the event is fired twice. My code is given below:
button.addEventListener("click", (event)=>{
if(!event.detail || event.detail && !event.detail.fromComponent){
let eventObject = new CustomEvent("click", {bubbles: true, composed: true, cancelable: true, detail: {myCustomKey: myCustomValue, fromComponent: true });
}
});
To avoid infinite looping, I have added boolean key*fromComponent in the detail object. Is there any way to achieve my requirement?

Related

Fire event programmatically indistinguishable from real user event (from extension/addon) [duplicate]

I'm trying to automatize some tasks in JavaScript and I need to use a InputEvent, but when I use normal event, I'm getting event.isTrusted = false and my event is doing nothing. Here is my event code:
var event = new InputEvent('input', {
bubbles: true,
cancelable: false,
data: "a"
});
document.getElementById('email').dispatchEvent(event);
This code should put "a" into a textField with id "email", but when event.isTrusted = false, this code is doing nothing. I'm testing it in Chrome Developer Tools in Sources tab with Event Listener Breakpoints (I checked only keyboard>input breakpoint and it shows me all attributes of used event).
I checked all attributes from real keyboard click and only thing that is different is event.isTrusted.
What can I change or what can I do to get event.isTrusted = true?
The isTrusted read-only property of the Event interface is a boolean that is true when the event was generated by a user action, and false when the event was created or modified by a script or dispatched via dispatchEvent.
Source: MDN
You may have misunderstood the concept of the Input Event, the event is triggered after the user type in the input. Manually triggering the event will not make the inputs change their values, is the changing of the values that makes the input trigger's the event not the opposite.
If you really want to change the value of the inputs with a custom event you can do something like this:
let TargetInput = document.getElementById('target')
let Button = document.getElementById('btnTrigger');
Button.addEventListener('click',function(e){
Trigger();
}, false);
TargetInput.addEventListener('input',function(e){
if(!e.isTrusted){
//Mannually triggered
this.value += e.data;
}
}, false);
function Trigger(){
var event = new InputEvent('input', {
bubbles: true,
cancelable: false,
data: "a"
});
TargetInput.dispatchEvent(event);
}
Target: <input type="text" id="target">
<hr>
<button id="btnTrigger">Trigger Event</button>
Any addEventListener call after the following code is executed will have isTrusted set to true.
Element.prototype._addEventListener = Element.prototype.addEventListener;
Element.prototype.addEventListener = function () {
let args = [...arguments]
let temp = args[1];
args[1] = function () {
let args2 = [...arguments];
args2[0] = Object.assign({}, args2[0])
args2[0].isTrusted = true;
return temp(...args2);
}
return this._addEventListener(...args);
}
Note: This is a very "hacky" way to go about doing this.
Unfortunately, you cannot generate event programmatically with isTrusted=true in Google Chrome and others modern browser.
See https://developer.mozilla.org/en-US/docs/Web/API/Event/isTrusted
Pupeeteer might help. It generates trusted events.
In browsers, input events could be divided into two big groups:
trusted vs. untrusted.
Trusted events: events generated by users interacting with the page,
e.g. using a mouse or keyboard. Untrusted event: events generated by
Web APIs, e.g. document.createEvent or element.click() methods.
Websites can distinguish between these two groups:
using an Event.isTrusted event flag
sniffing for accompanying events.
For example, every trusted 'click' event is preceded by 'mousedown'
and 'mouseup' events.
For automation purposes it’s important to
generate trusted events. All input events generated with Puppeteer are
trusted and fire proper accompanying events.
I've found it's not possible to set isTrusted to true BUT, depending on your need, a potential solution would be to create a local override in DevTools and remove the conditional in code for the script. This will tell Chrome to use your version (with the isTrusted check removed) instead of the site's JS file.

JavaScript trigger an InputEvent.isTrusted = true

I'm trying to automatize some tasks in JavaScript and I need to use a InputEvent, but when I use normal event, I'm getting event.isTrusted = false and my event is doing nothing. Here is my event code:
var event = new InputEvent('input', {
bubbles: true,
cancelable: false,
data: "a"
});
document.getElementById('email').dispatchEvent(event);
This code should put "a" into a textField with id "email", but when event.isTrusted = false, this code is doing nothing. I'm testing it in Chrome Developer Tools in Sources tab with Event Listener Breakpoints (I checked only keyboard>input breakpoint and it shows me all attributes of used event).
I checked all attributes from real keyboard click and only thing that is different is event.isTrusted.
What can I change or what can I do to get event.isTrusted = true?
The isTrusted read-only property of the Event interface is a boolean that is true when the event was generated by a user action, and false when the event was created or modified by a script or dispatched via dispatchEvent.
Source: MDN
You may have misunderstood the concept of the Input Event, the event is triggered after the user type in the input. Manually triggering the event will not make the inputs change their values, is the changing of the values that makes the input trigger's the event not the opposite.
If you really want to change the value of the inputs with a custom event you can do something like this:
let TargetInput = document.getElementById('target')
let Button = document.getElementById('btnTrigger');
Button.addEventListener('click',function(e){
Trigger();
}, false);
TargetInput.addEventListener('input',function(e){
if(!e.isTrusted){
//Mannually triggered
this.value += e.data;
}
}, false);
function Trigger(){
var event = new InputEvent('input', {
bubbles: true,
cancelable: false,
data: "a"
});
TargetInput.dispatchEvent(event);
}
Target: <input type="text" id="target">
<hr>
<button id="btnTrigger">Trigger Event</button>
Any addEventListener call after the following code is executed will have isTrusted set to true.
Element.prototype._addEventListener = Element.prototype.addEventListener;
Element.prototype.addEventListener = function () {
let args = [...arguments]
let temp = args[1];
args[1] = function () {
let args2 = [...arguments];
args2[0] = Object.assign({}, args2[0])
args2[0].isTrusted = true;
return temp(...args2);
}
return this._addEventListener(...args);
}
Note: This is a very "hacky" way to go about doing this.
Unfortunately, you cannot generate event programmatically with isTrusted=true in Google Chrome and others modern browser.
See https://developer.mozilla.org/en-US/docs/Web/API/Event/isTrusted
Pupeeteer might help. It generates trusted events.
In browsers, input events could be divided into two big groups:
trusted vs. untrusted.
Trusted events: events generated by users interacting with the page,
e.g. using a mouse or keyboard. Untrusted event: events generated by
Web APIs, e.g. document.createEvent or element.click() methods.
Websites can distinguish between these two groups:
using an Event.isTrusted event flag
sniffing for accompanying events.
For example, every trusted 'click' event is preceded by 'mousedown'
and 'mouseup' events.
For automation purposes it’s important to
generate trusted events. All input events generated with Puppeteer are
trusted and fire proper accompanying events.
I've found it's not possible to set isTrusted to true BUT, depending on your need, a potential solution would be to create a local override in DevTools and remove the conditional in code for the script. This will tell Chrome to use your version (with the isTrusted check removed) instead of the site's JS file.

Trigger keyboard event in vanilla javascript

I am trying to follow currently recommended way of triggering dom events (using event constructors that is) and it does not work for me (in Chrome)
This is my code (http://jsfiddle.net/artemave/shg7ot58/):
document.addEventListener(function(e) {
alert("hallo");
});
var e = new KeyboardEvent("keydown", {
key: "Escape", // keyCode: 27 also does not work
bubbles: true,
cancelable: true
});
document.dispatchEvent(e);
Add event type, keydown to the addEventListener method to listen for your custom dispatched event.
document.addEventListener('keydown', function(e) {
alert("hallo");
});
Fiddle: http://jsfiddle.net/shg7ot58/1/

Invoking KeyPress Event Without Actually Pressing Key

Just wondering. Is it possible to invoke a key press event in JavaScript without ACTUALLY pressing the key ? For example lets say, I have a button on my webpage and when that button is clicked I want to invoke a event as if a particular key has been pressed. I know it weird but can this be done in JavaScript.
Yes, this can be done using initKeyEvent. It's a little verbose to use, though. If that bothers you, use jQuery, as shown in #WojtekT's answer.
Otherwise, in vanilla javascript, this is how it works:
// Create the event
var evt = document.createEvent( 'KeyboardEvent' );
// Init the options
evt.initKeyEvent(
"keypress", // the kind of event
true, // boolean "can it bubble?"
true, // boolean "can it be cancelled?"
null, // specifies the view context (usually window or null)
false, // boolean "Ctrl key?"
false, // boolean "Alt key?"
false, // Boolean "Shift key?"
false, // Boolean "Meta key?"
9, // the keyCode
0); // the charCode
// Dispatch the event on the element
el.dispatchEvent( evt );
If you're using jquery:
var e = jQuery.Event("keydown");
e.which = 50; //key code
$("#some_element").trigger(e);

How do I programmatically force an onchange event on an input?

How do I programmatically force an onchange event on an input?
I've tried something like this:
var code = ele.getAttribute('onchange');
eval(code);
But my end goal is to fire any listener functions, and that doesn't seem to work. Neither does just updating the 'value' attribute.
Create an Event object and pass it to the dispatchEvent method of the element:
var element = document.getElementById('just_an_example');
var event = new Event('change');
element.dispatchEvent(event);
This will trigger event listeners regardless of whether they were registered by calling the addEventListener method or by setting the onchange property of the element.
By default, events created and dispatched like this don't propagate (bubble) up the DOM tree like events normally do.
If you want the event to bubble, you need to pass a second argument to the Event constructor:
var event = new Event('change', { bubbles: true });
Information about browser compability:
dispatchEvent()
Event()
In jQuery I mostly use:
$("#element").trigger("change");
ugh don't use eval for anything. Well, there are certain things, but they're extremely rare.
Rather, you would do this:
document.getElementById("test").onchange()
Look here for more options:
http://jehiah.cz/archive/firing-javascript-events-properly
For some reason ele.onchange() is throwing a "method not found" expception for me in IE on my page, so I ended up using this function from the link Kolten provided and calling fireEvent(ele, 'change'), which worked:
function fireEvent(element,event){
if (document.createEventObject){
// dispatch for IE
var evt = document.createEventObject();
return element.fireEvent('on'+event,evt)
}
else{
// dispatch for firefox + others
var evt = document.createEvent("HTMLEvents");
evt.initEvent(event, true, true ); // event type,bubbling,cancelable
return !element.dispatchEvent(evt);
}
}
I did however, create a test page that confirmed calling should onchange() work:
<input id="test1" name="test1" value="Hello" onchange="alert(this.value);"/>
<input type="button" onclick="document.getElementById('test1').onchange();" value="Say Hello"/>
Edit: The reason ele.onchange() didn't work was because I hadn't actually declared anything for the onchange event. But the fireEvent still works.
Taken from the bottom of QUnit
function triggerEvent( elem, type, event ) {
if ( $.browser.mozilla || $.browser.opera ) {
event = document.createEvent("MouseEvents");
event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
0, 0, 0, 0, 0, false, false, false, false, 0, null);
elem.dispatchEvent( event );
} else if ( $.browser.msie ) {
elem.fireEvent("on"+type);
}
}
You can, of course, replace the $.browser stuff to your own browser detection methods to make it jQuery independent.
To use this function:
var event;
triggerEvent(ele, "change", event);
This will basically fire the real DOM event as if something had actually changed.
This is the most correct answer for IE and Chrome::
var element = document.getElementById('xxxx');
var evt = document.createEvent('HTMLEvents');
evt.initEvent('change', false, true);
element.dispatchEvent(evt);
If you add all your events with this snippet of code:
//put this somewhere in your JavaScript:
HTMLElement.prototype.addEvent = function(event, callback){
if(!this.events)this.events = {};
if(!this.events[event]){
this.events[event] = [];
var element = this;
this['on'+event] = function(e){
var events = element.events[event];
for(var i=0;i<events.length;i++){
events[i](e||event);
}
}
}
this.events[event].push(callback);
}
//use like this:
element.addEvent('change', function(e){...});
then you can just use element.on<EVENTNAME>() where <EVENTNAME> is the name of your event, and that will call all events with <EVENTNAME>
The change event in an input element is triggered directly only by the user. To trigger the change event programmatically we need to dispatch the change event.
The question is Where and How?
"Where" we want the change event to be triggered exactly at the moment after a bunch of codes is executed, and "How" is in the form of the following syntax:
const myInput = document.getElementById("myInputId");
function myFunc() {
//some codes
myInput.dispatchEvent(new Event("change"));
}
In this way, we created the change event programmatically by using the Event constructor and dispatched it by the dispatchEvent() method. So whenever myFunc() method is invoked, after the //some codes are executed, our synthetic change event is immediately triggered on the desired input element.‍
Important result: Here, the change event is triggered by executing the //some codes in myFunc() instead of changing the input value by the user (default mode).
if you're using jQuery you would have:
$('#elementId').change(function() { alert('Do Stuff'); });
or MS AJAX:
$addHandler($get('elementId'), 'change', function(){ alert('Do Stuff'); });
Or in the raw HTML of the element:
<input type="text" onchange="alert('Do Stuff');" id="myElement" />
After re-reading the question I think I miss-read what was to be done. I've never found a way to update a DOM element in a manner which will force a change event, what you're best doing is having a separate event handler method, like this:
$addHandler($get('elementId'), 'change', elementChanged);
function elementChanged(){
alert('Do Stuff!');
}
function editElement(){
var el = $get('elementId');
el.value = 'something new';
elementChanged();
}
Since you're already writing a JavaScript method which will do the changing it's only 1 additional line to call.
Or, if you are using the Microsoft AJAX framework you can access all the event handlers via:
$get('elementId')._events
It'd allow you to do some reflection-style workings to find the right event handler(s) to fire.
Using JQuery you can do the following:
// for the element which uses ID
$("#id").trigger("change");
// for the element which uses class name
$(".class_name").trigger("change");
For triggering any event in Javascript.
document.getElementById("yourid").addEventListener("change", function({
//your code here
})

Categories