I have a textarea element on which I wan't to fire an event.
When setting up a listener and the element is disabled I get an inconsistent behavior. Chrome (64.0.3282.186), Safari (11.0.3) and Edge fires the event and everything looks good (as I would expect them to do) but in Firefox (58.0.2) the eventlistener does not fire.
Anyone got any idea on how to solve this without enabling the element?
var eventName = 'bar',
element = document.querySelector('#foo'),
event = new CustomEvent(eventName, {
cancelable: true,
bubbles: false,
detail: null
});
element.addEventListener(eventName, function() {
element.value = 'X';
});
element.dispatchEvent(event);
<textarea id="foo" disabled="disabled"></textarea>
Add an HTMLElement method that enables the element, dispatches the event and then disables it again afterwards.
HTMLElement.prototype.fireEvent = function(e) {
const isDisabled = this.hasAttribute('disabled');
this.removeAttribute('disabled');
this.dispatchEvent(e);
if (isDisabled)
this.setAttribute('disabled', true);
};
var eventName = 'bar',
element = document.querySelector('#foo'),
event = new CustomEvent(eventName, {
cancelable: true,
bubbles: false,
detail: null
});
element.addEventListener(eventName, function() {
element.value = 'X';
});
element.fireEvent(event)
<textarea id="foo" disabled="disabled"></textarea>
Granted, this modifies the native element which is frowned upon - you can avoid prototype methods and just write a plain old function, i.e fireEvent(elem, event).
I posted an bug to Mozilla on the matter as nothing is mentioned in the w3 spec that the element should not dispatch events when the element is disabled.
The only thing that is mentioned is that mouse events should not be dispatched.
https://www.w3.org/TR/2011/WD-html5-20110525/association-of-controls-and-forms.html#attr-fe-disabled
A form control that is disabled must prevent any click events that are queued on the user interaction task source from being dispatched on the element.
The bug can be found here:
https://bugzilla.mozilla.org/show_bug.cgi?id=1443148
Related
I am trying to automate somethings on some website
It has textarea and send btn (it all automatically generated with vue.js if it is matters, and this website is not mine)
<textarea class="index_textarea_1O4S1 mb2"></textarea>
<btn disabled='disabled> <span>send </span> </btn>
I need to set some text to textarea and press this button
But this code doesn't work
document.querySelector('textarea').textContent = "hello there"
document.querySelector('button').click()
As you can see btn stays disabled
I tried to remove disabled attribute of btn, but doesn't help also
So I guess the best option is to try to send keypress event to textarea
How do I do it?
BTW I don't know why but jquery $ functions seems to work strange from console on this website, so vanilla js is preferable
Assuming I understand correctly,
When I have run into this problem in the past, it's because there is some event listener that I'm trying to trigger and the element I send the event to is either targeting the wrong event or the wrong element. You can use dev tools to try and isolate the desired event, and you can send an event by creating it manually instead of calling the .click method.
For example:
const txtArea = document.querySelector('textarea');
txtArea.textContent = "hello there";
const inputEv = new Event("input", { bubbles: true });
const keydownEv = new Event("keydown", { bubbles: true });
const keyupEv = new Event("keyup", { bubbles: true });
txtArea.dispatchEvent(inputEv);
txtArea.dispatchEvent(keydownEv);
txtArea.dispatchEvent(keyupEv);
document.querySelector('button')
.dispatchEvent(new Event("click", { bubbles: true });
creating the event this way lets you even trigger custom events, once identified, by changing the first argument passed to the new Event constructor, and triggers parent elements by setting the option bubbles to true.
jQuery enables it like so:
$( "input" ).triggerHandler( "focus" );
How can I achieve the same without jQuery?
https://api.jquery.com/triggerHandler/
You use dispatchEvent on the element for which you want focus to be triggered. See the
docs and an example here.
const event = new FocusEvent('focus', {
view: window,
bubbles: true,
cancelable: true
});
const myInput = document.getElementById('myInput');
myInput.dispatchEvent(event);
#myInput:focus {
background: red;
}
<input id="myInput" type="text" onfocus="console.log('Input focused!');"/>
As you can see in the above code, the console.log statement is run based on the bound event to the input tag, but the element is not actually focused (because otherwise the input box would be red, which you can try by clicking on it).
Use the getEventListeners(node) function
In your case:
console.log(getEventListeners(document.getElementsByTagName('input')[0]));
You will get all the listeners, then you can filter those that are attached to the focus event
I have a jasmine test where I have 2 input fields. I am focusing on an first input, then simulating a keydown on the 'tab' key, and expecting focus to be on the second input. Unfortunately this is not the case. The focus does not change from the first and my test is failing. How can this be fixed so the failing test passes?
Fiddle of what I'm trying to test: http://jsfiddle.net/G2Qz3/1/
Fiddle of the failing Jasmine test: http://jsfiddle.net/mFUhK/4/
HTML:
<input id="first"></input>
<input id="second"></input>
JavaScript:
function simulateTab() {
var TAB_KEY = 9;
var keyboardEvent = document.createEvent("KeyboardEvent");
var initMethod = typeof keyboardEvent.initKeyboardEvent !== 'undefined' ? "initKeyboardEvent" : "initKeyEvent";
keyboardEvent[initMethod]("keydown", true, true, window, 0, 0, 0, 0, 0, TAB_KEY);
document.dispatchEvent(keyboardEvent);
}
describe('input tabbing test', function() {
beforeEach(function() {
document.getElementById('first').focus();
});
//this passes
it('input with id "first" should be focussed', function() {
expect(document.activeElement.getAttribute('id')).toBe('first');
});
//this fails
it('input with id "second" should be focussed after tabbing', function() {
simulateTab();
expect(document.activeElement.getAttribute('id')).toBe('second');
});
});
This cannot be done. See this SO question, which is based on this tutorial which says:
Note that manually firing an event does not generate the default action associated with that event. For example, manually firing a focus event does not cause the element to receive focus (you must use its focus method for that), manually firing a submit event does not submit a form (use the submit method), manually firing a key event does not cause that letter to appear in a focused text input, and manually firing a click event on a link does not cause the link to be activated, etc. In the case of UI events, this is important for security reasons, as it prevents scripts from simulating user actions that interact with the browser itself.
I'm trying to use JavaScript events to check an input checkbox in JSDOM.
<input type="checkbox" id="foo" />
But I can't seem to get it to check itself by dispatching an event on it:
var evt = document.createEvent("HTMLEvents");
evt.initEvent("click", false, true);
document.querySelector('#foo').dispatchEvent(evt)
However, it does work when I use jQuery's .trigger('click')
Why doesn't this code work in jsdom? I feel there's some minor inconsistency in jsdom and likely some other browser which jQuery fixes.
There is a browser dependency on the way you can manually trigger events in JavaScript.
Here's a demo.
The Code:
document.getElementById("foo").value='500';
if (document.getElementById("foo").fireEvent) {
document.getElementById("foo").fireEvent("onclick");
} else if (document.getElementById("foo").dispatchEvent) {
var clickevent=document.createEvent("MouseEvents");
clickevent.initEvent("click", true, true);
document.getElementById("foo").dispatchEvent(clickevent);
}
Updated Fiddle
Updated Code:
if (document.getElementById("foo").fireEvent) {
document.getElementById('car-make').attachEvent('onchange', update);
document.getElementById("foo").fireEvent("onchange");
} else if (document.getElementById("foo").dispatchEvent) {
document.getElementById('foo').addEventListener('change', update, false);
var clickevent=document.createEvent("MouseEvents");
clickevent.initEvent("change", true, true);
document.getElementById("foo").dispatchEvent(clickevent);
}
function update () {
alert('changed');
}
From the specs:
The change event occurs when a control loses the input focus and its value has been modified since gaining focus. This event is valid for INPUT, SELECT, and TEXTAREA. element.
Bubbles: Yes
Cancelable: No
Context Info: None
Note how this is different from the click event, for example:
The click event occurs when the pointing device button is clicked over an element.
Thus, triggering a change event will not actually change the input value.
Loosely speaking, the Cancelable: No property says that nothing will happen by default.
Some simple event driven code. For whatever reason, I can't seem to pass 'onchange' as a parameter to fireEvent(). Throws me an invalide argument error in ie 7/8. This project needs to be native. Little help?
Custom Event Creation:
createCustomEvent : function(eventName) {
var evt;
if(document.createEvent) {
evt = document.createEvent('CustomEvent');
evt.initEvent(eventName, true, true);
}else if(document.createEventObject) {
evt = document.createEventObject();
evt.eventName = eventName;
}
return evt;
},
dispatchCustomEvent : function (el, evt) {
if(el.dispatchEvent) {
el.dispatchEvent(evt);
}else if(el.fireEvent) {
console.log('on'+evt.eventName); //onchange
el.fireEvent('on'+evt.eventName, evt);
}
}
Usage:
dispatchCustomEvent(element, createCustomEvent('change'));
Okay, so according to most docs the change event will fire on any element and I quote:
"The change event is fired when an element loses focus and its value changed since gaining focus."
https://developer.mozilla.org/en-US/docs/DOM/Mozilla_Event_Reference/change
However, in <= ie8 onchange will not fire on any element besides form elements. This is incredibly lame imo, and makes modern MVC custom event listening and dispatching an issue.
Long story short, in my case I used the blur event to capture changes to my div element. This worked for me as the focus is removed between div element updates. It's a slideshow application, where two divs pop on and off the stack, left to right depending on the current location.