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.
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 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
I want to fire an event in a textarea immediately after paste some text inside the textarea. I can do that when Shift+Ins is used; however, I cannot do it when right mouse button and then paste (from the drop down menu) is chosen. Keyup fires after Shift+Ins. None of the rest fires when Paste is chosen after right mouse button clicking... What do I have to do?
<textarea name="message" id="message"></textarea>
$("#message").on('keyup contextmenu', function(event) {
alert("ok");
});
http://jsfiddle.net/f29vuwoL/7/
Thank you
Most browsers support the input event, which is fired when something is pasted or otherwise added, regardless of how:
$("#message").on('keyup contextmenu input', function(event) {
alert("ok");
});
Updated Fiddle
Note that using input is the most general method, firing when the control gets input regardless of how, and so if you hook multiple events (as above), you'll get multiple calls for the same input. For instance, if you hook both keyup and input, on browsers that support input, you'll get two calls. Similarly for paste and input when the user pastes, on browsers that support both.
If you need to support browsers that don't have either input or paste, I'm afraid the unfortunate answer is that you need to poll. Still, polling every (say) 250ms isn't asking the browser to do that much work, and you can feature-detect whether it's necessary:
var message = $("#message");
var events = null;
var previous;
if ('oninput' in message[0]) {
// Browser supports input event
events = "input";
} else if ('onpaste' in message[0]) {
// Browser supports paste event
events = "paste keyup contextmenu";
}
if (!events) {
// Ugh, poll and fire our own
events = "pseudoinput";
previous = message.val();
setInterval(function() {
var current = message.val();
if (current != previous) {
previous = current;
message.trigger(events);
}
}, 250);
}
console.log("Using: " + events);
message.on(events, function(e) {
console.log("Got event: " + e.type);
});
Updated Fiddle
You should use input event callback. See the demo here
You can use the dedicated paste event:
$("#message").on('paste', function(event) {
alert("ok");
});
Updated jsFiddle
However you might want to check browser support - I don't think jQuery normalizes this event.
If you need IE support, it might be a little more difficult, but it depends on your requirements - does it absolutely need to be a paste action? If not, TJ Crowder's answer is the way to go.
The on input is useful if you want to detect when the contents of a textarea, input:text, input:password or input:search element have changed, because the onchange event on these elements fires when the element loses focus, not immediately after the modification.The oninput event is supported in Internet Explorer from version 9.
$("#message").on('input propertychange', function() {
console.log($(this).val());
});
Fiddle
How come the following code does not work. I prevent the default action on the event. Then I want to check the box anyway.
html
<input type="checkbox" class="checkbox" />
javsacript
$('.checkbox').click( function(e) {
e.preventDefault();
// some logic happens... now i may decide to check the box (in this case we want to check it for testing)
$('.checkbox').prop('checked',true);
});
You would think clicking the checkbox would still check the box.. but it doesnt. Check the fiddle to see what I mean.
http://jsfiddle.net/5KDH8/
I have also tried using the attr function without any luck.
You have to put the code that sets the "checked" property in a separate event loop:
setTimeout(function() { $('.checkbox').prop('checked', true); }, 1);
Either the browser or the library has to un-set the checkbox after the event handler returns, because it sets it in response to the click before the handler is invoked.
$('.checkbox').click( function(e) {
// do some logic that returns true or false
if (!mylogic) {
return false;
// returning false will prevent the checkbox to be checked.
}
});