I'm trying to build a shortcut expander, so when a user types a certain sequence of characters, it's replaced with some longer sentence.
I'm currently using 'input' event to capture contenteditable changes. The issue is, pasting also triggers the 'input' event. I only want the event to fire when user types in a character. Is there any way to do this?
The simplest solution would be to detect a keyboard event (keydown, keyup or keypress) instead of oninput, but which to choose, depends on what the handler actually will do.
If you don't want/can't use keyboard detection, there's a back-gate. It looks like onpaste would fire before oninput (Chrome, FF). Hence you could create a flag for paste, and check it in oninput handler. Something like this:
var pasted = false,
pad = document.getElementById('pad'); // The contenteditable
pad.addEventListener('paste', function (e) {
pasted = true;
});
pad.addEventListener('input', function (e) {
if (pasted) {
pasted = false;
return;
}
console.log('keyboard, cut or drop');
});
A live demo at jsFiddle.
Notice, that oninput is fired also ondrop and oncut as well as onpaste and typing in. If you don't want to handle any of these events in oninput handler, you've to listen all these events, and set a flag accordingly.
As a sidenote, IE doesn't fire oninput on contenteditables. If you want to support IEs, you need to use onkeypdown/up-onpaste-oncut-ondrop combination to achieve something similar to oninput.
Related
I'm writing a form validation script and would like to validate a given field when its onblur event fires. I would also like to use event bubbling so i don't have to attach an onblur event to each individual form field. Unfortunately, the onblur event doesn't bubble. Just wondering if anyone knows of an elegant solution that can produce the same effect.
You're going to need to use event capturing (as opposed to bubbling) for standards-compliant browsers and focusout for IE:
if (myForm.addEventListener) {
// Standards browsers can use event Capturing. NOTE: capturing
// is triggered by virtue of setting the last parameter to true
myForm.addEventListener('blur', validationFunction, true);
}
else {
// IE can use its proprietary focusout event, which
// bubbles in the way you wish blur to:
myForm.onfocusout = validationFunction;
}
// And of course detect the element that blurred in your handler:
function validationFunction(e) {
var target = e ? e.target : window.event.srcElement;
// ...
}
See http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html for the juicy details
use 'Focusout' event as it has Bubble up effect..thanks.
ppk has a technique for this, including the necessary workarounds for IE: http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
aa, you can simply add the onblur event on the form, and will call the validation every time you change focus on any of the elements inside it
When using jquery .change on an input the event will only be fired when the input loses focus
In my case, I need to make a call to the service (check if value is valid) as soon as the input value is changed. How could I accomplish this?
UPDATED for clarification and example
examples: http://jsfiddle.net/pxfunc/5kpeJ/
Method 1. input event
In modern browsers use the input event. This event will fire when the user is typing into a text field, pasting, undoing, basically anytime the value changed from one value to another.
In jQuery do that like this
$('#someInput').bind('input', function() {
$(this).val() // get the current value of the input field.
});
starting with jQuery 1.7, replace bind with on:
$('#someInput').on('input', function() {
$(this).val() // get the current value of the input field.
});
Method 2. keyup event
For older browsers use the keyup event (this will fire once a key on the keyboard has been released, this event can give a sort of false positive because when "w" is released the input value is changed and the keyup event fires, but also when the "shift" key is released the keyup event fires but no change has been made to the input.). Also this method doesn't fire if the user right-clicks and pastes from the context menu:
$('#someInput').keyup(function() {
$(this).val() // get the current value of the input field.
});
Method 3. Timer (setInterval or setTimeout)
To get around the limitations of keyup you can set a timer to periodically check the value of the input to determine a change in value. You can use setInterval or setTimeout to do this timer check. See the marked answer on this SO question: jQuery textbox change event or see the fiddle for a working example using focus and blur events to start and stop the timer for a specific input field
If you've got HTML5:
oninput (fires only when a change actually happens, but does so immediately)
Otherwise you need to check for all these events which might indicate a change to the input element's value:
onchange
onkeyup (not keydown or keypress as the input's value won't have the new keystroke in it yet)
onpaste (when supported)
and maybe:
onmouseup (I'm not sure about this one)
With HTML5 and without using jQuery, you can using the input event:
var input = document.querySelector('input');
input.addEventListener('input', function()
{
console.log('input changed to: ', input.value);
});
This will fire each time the input's text changes.
Supported in IE9+ and other browsers.
Try it live in a jsFiddle here.
As others already suggested, the solution in your case is to sniff multiple events.
Plugins doing this job often listen for the following events:
$input.on('change keydown keypress keyup mousedown click mouseup', handler);
If you think it may fit, you can add focus, blur and other events too.
I suggest not to exceed in the events to listen, as it loads in the browser memory further procedures to execute according to the user's behaviour.
Attention: note that changing the value of an input element with JavaScript (e.g. through the jQuery .val() method) won't fire any of the events above.
(Reference: https://api.jquery.com/change/).
// .blur is triggered when element loses focus
$('#target').blur(function() {
alert($(this).val());
});
// To trigger manually use:
$('#target').blur();
If you want the event to be fired whenever something is changed within the element then you could use the keyup event.
There are jQuery events like keyup and keypress which you can use with input HTML Elements.
You could additionally use the blur() event.
This covers every change to an input using jQuery 1.7 and above:
$(".inputElement").on("input", null, null, callbackFunction);
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)
In text fields of my JSP, I wish to know whether user is typing in the data or just pasting.
How can I identify this using javascript ?
EDIT: As per Andy's answer I know how I can go about it, but still curios how those guys wrote onpaste event.
Safari, Chrome, Firefox and Internet Explorer all support the onpaste event (not sure about Opera). Latch onto the onpaste event and you will be able to catch whenever something is pasted.
Writing this is simple enough. Add the event handler to your input using html:
<input type="text" id="myinput" onpaste="handlePaste(event);">
or JavaScript-DOM:
var myInput = document.getElementById("myInput");
if ("onpaste" in myInput) // onpaste event is supported
{
myInput.onpaste = function (e)
{
var event = e || window.event;
alert("User pasted");
}
}
// Check for mutation event support instead
else if(document.implementation.hasFeature('MutationEvents','2.0'))
{
/* You could handle the DOMAttrModified event here, checking
new value length vs old value length but it wouldn't be 100% reliable */
}
From what I've read, Opera does not support the onpaste event. You could use the DOMAtrrModified event, but this would fire even when scripts change the value of the input box so you have to be careful with it. Unfortunately, I'm not familiar with mutation events so I wouldn't like to mess this answer up by writing an example that I wouldn't be confident of.
Count the key presses and make sure it matches whats in the text box a paste will not have complete number of characters as is in the text box.
You will never know for sure. Even when intercepting key input, the use may have used the context menu to paste using the mouse. Accessing the clipboard (to compare the input with the clipboard contents) will not work the way you want because it is a strict user-only operation. You are not able to access is programmatically without the explicit consent of the user (the browser will show a confirmation message).
I know for textarea you can capture on paste event using the onPaste event.
HTML:
<textarea id="textEditor" />
In JS:
var editor = document.getElementById("textEditor");
if (isIE /* determine this yourself */) {
editor.onPaste = function() {
}
} else {
//Not IE
editor.onpaste = function() {
}
}
//The capitalisation of the onpaste (non-IE) and onPaste (IE) makes a difference.
As for typing, there's onKeyDown, onKeyUp, onKeyPress events.
Hope this helps.
Possible SO-related question IE onPaste event using javascript not HTML
I'm writing a form validation script and would like to validate a given field when its onblur event fires. I would also like to use event bubbling so i don't have to attach an onblur event to each individual form field. Unfortunately, the onblur event doesn't bubble. Just wondering if anyone knows of an elegant solution that can produce the same effect.
You're going to need to use event capturing (as opposed to bubbling) for standards-compliant browsers and focusout for IE:
if (myForm.addEventListener) {
// Standards browsers can use event Capturing. NOTE: capturing
// is triggered by virtue of setting the last parameter to true
myForm.addEventListener('blur', validationFunction, true);
}
else {
// IE can use its proprietary focusout event, which
// bubbles in the way you wish blur to:
myForm.onfocusout = validationFunction;
}
// And of course detect the element that blurred in your handler:
function validationFunction(e) {
var target = e ? e.target : window.event.srcElement;
// ...
}
See http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html for the juicy details
use 'Focusout' event as it has Bubble up effect..thanks.
ppk has a technique for this, including the necessary workarounds for IE: http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
aa, you can simply add the onblur event on the form, and will call the validation every time you change focus on any of the elements inside it