Javascript: invoke default keydown event handler - javascript

I'd like to invoke default keydown event handler from javascript. Is it possible?

If the event has an explicit event handler you can just invoke it directly:
// Precondition - the element has an explicit handler registered
element.onkeydown();
Otherwise, there's no way to explicitly tell the browser to do "what it would have done anyway". The only way to get this to happen is to not stop the event from bubbling - which can be a real pain if you want to set a timeout and then allow the event to continue, it's essentially not possible.
In most cases, though, you can invoke your own code on an event handler and let the keyDown event continue to the browser. And if this isn't possibel for whatever reason, you can usually write your own method that will simulate the effects of the event (e.g. change the content of an input field, submit the form, etc.)

There is no default keydown event. The keydown event occurs when the key is pressed on any form elements, followed immediately by the keypress event, and possibly the textInput event on text box when you enter a value. Then the keyup event is generated when the key is released
The following example shows the use of the onKeyDown event handler to display a message in the text box.
<body><form action="" method="POST" id="myForm"><input type="text" name="myText" onKeyDown="changeVal()"><script type="text/javascript" language="JavaScript">s1 = new String(myForm.myText.value)function changeVal() { s1 = "You pressed a key"
myForm.myText.value = s1.toUpperCase() }</script></form></body>

Related

How to determine ordering of event listeners in Javascript

I'm confused by the ordering of event listeners in Javascript. If I have a form with a submit button and I'd like to alert a user instead of automatically submitting the form, but only when the submit using the Enter key, I can create an event listener for an Enter keypress, event.preventDefault(), etc.
Why is it that the default onsubmit event listener for the form is not triggered first?
Events do follow the law of causality. Smaller primitives build up larger, more important ones:
keydown -> keyup -> keypress -> change
mousedown -> mouseup -> click -> submit
In your case, the Enter keypress event causes the submit event.
Preventing the default action of an event will suppress the ensuing ones. They can't happen in reverse.

How to change input/textarea value with custom keyboard event and keyCode?

I would like to populate a textarea by triggering keyboard events, such as keydown (I'm doing this for a test case).
I have added a snippet (below) to show the code I'm using to create and trigger the event. The event fires, but the textarea never receives the value of keyCode which is the letter A.
What do I need to do to see the letter in the textarea? I'm currently running the snippet in the Chrome console but it should also work in IE9.
var t = document.getElementById('foo');
// Event creation
var event = document.createEvent('HTMLEvents');
event.initEvent('keydown', true, true);
event.keyCode = 65;
event.which = 65;
// Listener for demo purpose
t.addEventListener('keydown', function (e) {
document.getElementById('fired').value = e.type + ' fired';
});
// Event trigger
t.dispatchEvent(event);
<textarea id="foo"></textarea>
<br>
<input id="fired" value="">
The keydown event is fired when a key is pressed down but it's not the responsible for write the data in the DOM elements.
The thing is; If the user writes on the <textarea> first the character is added to elements value and then the keyDownevent is triggered. However in your case you're directly triggering the event so the first step which is adding the character to the value for <textarea> is not happening.
You have two options, do it in the browser way write the value and then dispatch the event
t.value = t.value + String.fromCharCode(e.keyCode);
t.addEventListener('keydown', function (e) {
document.getElementById('fired').value = e.type + ' fired';
});
Or also you can write the value of the <textarea> on the keyDown event:
// Listener for demo purpose
t.addEventListener('keydown', function (e) {
t.value = t.value + String.fromCharCode(e.keyCode);
document.getElementById('fired').value = e.type + ' fired';
});
however if you want to use this second approach for user interaction it's a nonsense because in the case that the users inputs the data, the data will be write it twice (one for the user input and the another one in the event).
Hope this helps,
Javascript sending key codes to a <textarea> element
I had a look around and this seems more relevant than my non-relevant answer before. Sorry about that. I know this is jquery, but the premise is the same.
adding this in the event would work
document.getElementById('foo').innerHTML += String.fromCharCode(e.keyCode);
here it is in pure javascript jsfiddle
Why does not the value change after triggering keydown?
In short: you can't change the value of input/texarea with dispatching KeyboardEvent programmatically.
How actually do chars come into input? On MDN you can find the description of Keyboardevent sequence (assuming that preventDefault is not called):
A keydown event is first fired. If the key is held down further and the key produces a character key, then the event continues to be emitted in a platform implementation dependent interval and the KeyboardEvent.repeat read only property is set to true.
If the key produces a character key that would result in a character being inserted into possibly an <input>, <textarea> or an element with HTMLElement.contentEditable set to true, the beforeinput and input event types are fired in that order. Note that some other implementations may fire keypress event if supported. The events will be fired repeatedly while the key is held down.
A keyup event is fired once the key is released. This completes the process.
So, keydown leads to input event by default. But that is true only for trusted events:
Most untrusted events will not trigger default actions, with the exception of the click event... All other untrusted events behave as if the preventDefault() method had been called on that event.
Basically trusted events are those initiated by a user and untrusted events are initiated with a script. In most browsers, each event has an attribute isTrusted indicating if the event is trusted or not.
And how to test KeyboardEvents on inputs then?
Well, first of all, think if you really need a KeyboardEvent handler. Maybe you can do everything in InputEvent handler. That means that you can just set the value of the input in your tests and then trigger InputEvent.
If you still need KeyboardEvent handler than it depends on what is going on in it. E.g. if you call preventDefault in certain conditions then you can check if it was called or not in a test using a spy. Here is an example with sinon as a spy and chai as assertion library.
const myEvent = new KeyboardEvent('keydown', { key: 'a' })
sinon.spy(myEvent, 'preventDefault')
document.getElementById('foo').dispatchEvent(myEvent)
expect(myEvent.preventDefault.calledOnce).to.equal(true)

Determining whether focus was received as result of a click event

I have an <input> element that can either have the focus set via code, or as the result of a mouse click.
If the user clicks on the input, then the click event handler will fire - all well and good. If the element receives the focus via some other way (e.g. via code) then I want to manually trigger the click event so that the handler will also fire.
I could do this:
$elem = $('input');
$elem
.on('focus', function() { $(this).trigger('click') })
.on('click', function() { alert('Clicked!') });
However, this will result in click handler being fired twice; once for the click event and once for the focus event.
Is there any way to selectively trigger the click handler only if the focus was not received as the result of a click event?
UPDATE
This is a very simplified version of my problem, so I can't do things like bind both handlers to the focus event etc. I'm trying to merge two third-party pieces of code.
The .trigger() function adds a property isTrigger in the event object to identify that the event was triggered by its usage. Although, it is not documented the property is still present in jQuery 1.8.3 but it seems to only be used internally.
Anyways, you can make use of the extraParameters parameter to add a custom property to the event object. For instance,
$(this).trigger('click', {
isTrigger: true
});
It will keep the compatibility with isTrigger even if it is gone in a future release.
After doing some more research it appears that there is no way of guaranteeing which event will fire first: click or focus. (There doesn't seem to be a standard that dictates the order of events.)
This means that when the focus event fires there's no way to determine if a click event will or will not be triggered by the browser shortly afterwards.
I managed to solve the issue by using setTimeout() to run a test about 100ms after the focus event fired to check if the click event had fired. The third-party code that I was using (bound to the click event) added an extra class to the <input>, so I was able to check for that.
You can tap into the mousedown event which fires before the focus event. When you click a focusable object the order of events is as follows... mousedown, focus, mouseup, click.
You could set a flag in the mousedown event and then check for it in the focus event to see if the focus came from a mouse click. Obviously make sure to clear the flag in the focus event handler. Every application is different, but tapping into the mousedown event allows you to figure out a solution.
Here is a JSFiddle demonstrating the order of events... http://jsfiddle.net/ek7v7/
$elem = $('input');
$elem
.on('focus', function() { alert("Focused!") })
Focus can be fired by focusing the input by using tab, clicking it, or by using .focus()
Is there a reason for on('click', ...)?

performing a javascript event without triggering that event handler

In my latest code, I have an event handler for a focus on a textarea. When the user clicks on the textarea, that event-handler is triggered which sets some other DOM states based on the selected textarea. However, elsewhere in my program I want to programmatically set the focus of the textarea without triggering that event handler. I know Backbone, for instance, has a way to silently perform an action.
My only pseudo-solution is to temporarily set a variable:
var silence = true;
And then, in my event handler, only perform the logic if silence is false. The handler is still triggered, but the logic doesn't run.
Does anyone else know of better strategies for this?
You could temporarily unbind() the event, like this:
You have the following scenario where you handle the focus event:
function focus_handler() {
//focus handler code
...
...
}
$('#yourelement').bind('focus', focus_handler);
And now on the part of the code where you want to programmatically focus the element without triggering the event handler:
$('#yourelement').unbind('focus');
$('#yourelement').focus();
$('#yourelement').bind('focus', focus_handler);
<input type="text" name="input" id="input" value="0">
<input type="text" name="input" id="input2" value="0">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js" type="text/javascript"></script>
<script>
$(function() {
$('#input').focus(function(a,b) {
if (b) alert('forced');
});
$('#input').trigger('focus', jQuery.Event("focus"));
});
</script>
When b argument of the event handler is present, the event is triggered by invoking $('#input').trigger('focus', jQuery.Event("focus"));. So you can make you handler function execute depending on normal focus or forced focus.
In jQuery, trigger() can take an event namespace. Only events bound with this namespace, and default behaviour, will be triggered.
So for example:
$('#yourelement').trigger('focus.anyOldNonsense');
should do the trick (provided no-one has used "anyOldNonsense" as an event namespace).
Edit: This works in 1.7.2 and 1.8.3, but there is a known bug in 1.9 onwards for adding data and namespaces to a "focus" event.
Since you can't prevent the event from happening, you need some kind of intermediary that decides whether or not to emit the event. So you would have the intermediary listen for all focus events and you'd have to tell that intermediary whether or not to re-emit the event. Then you'd listen on that intermediary rather than the dom node directly.
click here
try this hack to set onClick functions with params without firing them on instantiation.

Focus event with dispatchEvent

When I trigger a focus event with dispatchEvent on an input box, its onfocus is called, but on the UI the input box is not focused.
Is there any reason for this behavior?
var test = document.getElementById("test");
test.onfocus = function(event) {
console.log('focused');
}
var e = document.createEvent('Event');
e.initEvent("focus", true, true);
test.dispatchEvent(e);
On the other hand this works as expected.
var test = document.getElementById("test");
test.focus();
The reason i'm investigating this is that I use ZeptoJS to trigger events and it uses dispatchEvent.
The element you fire an event on does not have to be listening for that event, since potentially, the parent element may also be listening for that event.
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.
Also note that you should use fireEvent(), if you are working on IE. Also, the main difference between the dispatchEvent and fireEvent methods is that the dispatchEvent method invokes the default action of the event, the fireEvent method does not.
so for the solution please try this
test.onfocus = function(event) {
console.log('focused');
if( ! test.hasFocus() ) {
test.focus();
}
}

Categories

Resources