I'm catching paste events with $('selector').on('input', function(event) { ... });
Then I'm trying to test what's been pasted and if it doesn't pass validation, cancel the paste with event.preventDefault(). Unfortunately, by the time the listener function is executed, the text has already been pasted and event.preventDefault() does nothing.
So what's a good way to catch paste events, and if what's been pasted doesn't validate, undo/prevent the paste?
I know I can use .on('paste', function(event) { ... }), but that doesn't give me the text that's been pasted or the contents of the input element after the paste, unless I use setTimeout() with some minute wait time, and I'd like to avoid using setTimeout().
First of all some background on event trigger order for the input element:
keydown -> keypress -> paste -> input -> keyup -> change
Whenever you call preventDefault it stops the chains, like nothing happened.
So my suggestion is to catch the paste event, prevent its default behavior and do your logic there.
I know I can use .on('paste', function(event) { ... }), but that
doesn't give me the text that's been pasted or the contents of the
input element after the paste
Actually you can retrieve the content of the clipboard. See this doc. Support is all major browser (but only IE11+). I do not know if by the time of the writing of the question this functionality was available or not.
Fiddle example
$('#myInput').on('paste', function(e) {
// Cancel the event - this prevents the text from being entered into the input and stops the event chain
e.preventDefault();
// Get the content of the clipboard
let paste = (event.clipboardData || window.clipboardData).getData('text');
// Validate what it is pasted
if (paste == "text to paste") {
// If condition is satisfied manually set the value of the input
$(this)
.val(paste)
// Manually trigger events if you want
.trigger('input')
.trigger('change');
}
});
Notes on the code:
This solution does not include setTimeout. Whenever you make it with setTimeout you see for a very short time the text being pasted, like a blinking effect.
If text meets condition I manually set it in the input. However this does not trigger input and change events. If you need them, just manually trigger them
Similar approach is to first check the text and if it does not meet requirements then call preventDefault, otherwise do nothing. This way you avoid manually setting value in the input and triggering events afterward.
Try using .change event of jquery.
Set value to blank if value doesn't satisfy your condition.
Using
$('selector').on('input', function(event) { ... });
and in case the validation does not pass deleting the pasted text seems to work for me.
Sadly accessing the clipboard has some flaws (browser asking if it is allowed to inspect the clipboard, cross browser compatibility, etc.)
If you are okay with saving the last value of the input, the pasted text can be calculated anyway.
Here is my approach for calculating the pasted text
https://jsfiddle.net/f710o9qd/2/
I hope this helps you :)
(Feel free to refine the calculation of the pasted text if you find any flaws)
My understanding from the question is, we must not allow any data to be pasted inside the text box until and unless it pass a specific validation. Instead of using event.preventDefault(), we can capture the value when user input any content, using on('input') listener and validate it against the specific condition and if the validation gets failed, empty the text box value.
(This is the workaround if we still need to use on('input') event listener)
Sample Code (I am using console.log() for printing the pasted value):
HTML:
<input type='text' id="selector" />
JS:
$(document).ready(function() {
$('#selector').on('input', function (e){
if(e.target.value !== "myValue"){
$('#selector').val('');
}
else{
console.log(e.target.value);
}
});
});
Related
I have a search field that triggers an autocomplete search while typing. I have it trigger on keyup. This works perfectly in most browsers, but in Firefox on Android, this does not work. It seems like the keyup event is not triggered while typing. This only happens if word suggestions is turned on in the Android keyboard settings.
I see on Google search that the autocomplete search works there for the same setup, so it is obviously possible to do. I wonder how? Is it a special event I need to listen to for this to work?
Additionally I have tried to listen to the events change, keydown and keypress, but none is triggered.
HTML:
<input type="text" id="searchField"
autocomplete="off" spellcheck="false" autocorrect="off" />
jQuery event binding:
$('#searchField').keyup(function (e) {
var searchValue = $(this).val();
searchApi._executeAutocomplete(searchValue);
});
Note:
Sometimes, the key event is triggered, which is typically hitting a key that is not resulting in the process of forming a word. The most obvious here is Enter, which always triggers. Another is Space, which triggers because no word contain a space since space is the definition of a word completed. Backspace triggers if the the last character deleted was not within a word. This means it triggers if you just deleted the last remaining letter of a word (so it is the start of the field, or cursor following a space), but not if you deleted some characters at the end of a word where the cursor is still immediately following a letter. Basically, the key event is not triggered if the key press results in some kind of word suggestion from the keyboard app.
As a side note, I can say that everything works fine in Chrome on the same device.
You can use the input event instead, that worked for me in Firefox on Android.
You could bind event handlers to both input and keyup events for backwards compatibility, but in most modern browsers this will fire both:
$('#searchField').bind('input keyup', function(e){
var searchValue = $(this).val();
searchApi._executeAutocomplete(searchValue);
});
Example here:
http://jsfiddle.net/JQ928/3/
I found a solution in this answer to another question. The question was a basically "duplicate the text I write dynamically into another part of the page". The answer was including support for catching changes by non-keyboard actions, like pasting text using mouse. It was solved by starting a sniffer on focus in the text field that checks if the value has changed using setInterval(...). It clears the timer on blur.
This solved my problem which was basically that the key events didn't trigger, as well as the "paste by mouse" issue that I didn't realize was a problem until I found this answer...!
This works, but I'm not sure I am totally happy with this solution, because it uses a sniffer. I would be more happy with using some sort of event that is triggered on value change no matter what the cause of the change is. Using the change event would not work, as that is not triggered until focus leaves the field.
Trough the fact that Firefox on Android doesn't trigger key-events, but also triggers the input-event some kind of weird, (like if you press one key two events get triggerd, and it also triggers the input-event if you leave the input) I had to write my own event:
(function($){
var $event = $.event,
$special = $event.special.fennecInput = {
setup: function(){
$(this).on('input',$special.handler);
},
teardown: function(){
$(this).off('input',$spceial.handler);
},
handler: function(event) {
var context = this,
args = arguments,
dispatch = function() {
event.type='fennecInput';
$event.dispatch.apply(context,args);
};
if($(context).val() != $(context).attr('data-fennecInput-oldval')){
dispatch();
$(context).attr('data-fennecInput-oldval',$(context).val());
}
}
};
})(jQuery);
this event gets only triggered if an input-event happens that changes the value, so it doesn't execute events unnecessary.
events: { "paste .youtube-url" : "addUrl" }
addUrl: function(){
console.log(this.$(".youtube-url").val());
So lets say I paste "bad" into the textbox first time
console output: (an empty string)
then if I paste append something like "coder"
console output: bad
instead of whats inside the box "badcoder", I guess this i because the pseudo paste event is fired before the text is inserted.
Instead of using the paste event you could use the keyup event which fires if someone pastes but also only fires after the value for the input has been updated.
UPDATE
Good comment from #Micah (and #JohnnyO). Here's a fix I found to work:
$('input').on('paste', function () {
var that = this;
setTimeout(function () {
alert(that.value);
}, 0);
});
This sets a timeout so the code that reads the input's value is only run after the rest of the code in the stack has been run. I've only tested in Chrome 21 but the zero-time-timeout seems to do the trick.
Demo: http://jsfiddle.net/H4K4R/
The answer by #Jasper only works when pasting by keyboard. When using the mouse and the context menu to paste, you won't get a keyup event. The best event to watch for is the 'input' event. Unfortunately, for IE versions before 9, you'll need to watch for the 'propertychange' event instead because they don't support 'input'. 'propertychange' doesn't bubble, so you won't be able to wire up this event like you're doing using Backbone, and instead will need to bind it directly to the '.youtube-url' element.
Ok, so we all know that onChange is used to execute javascript code on a select statement when the option changes. However, if you change a select statement using the arrow keys, the onChange event is not called. Is there a way around this? Please help! I'm OCD I know.
--EDIT 1--
Just tested this in IE and arrow keys do work. Apparently it's just Chrome. ** Goes to check firefox
-- Edit 2 --
Tested in Firefox and realized just before an answer below talked about the onBlur action being required for the change. So the answer here is:
Internet Explorer recognizes onChange events from the keyboard as well as clicking on them.
Firefox and Chrome both require key events to be followed by blur event in order to call onChange.
Now normally, I don't like Internet Explorer, because it's a piece of garbage... But I think I... unfortunately, have to say they got that one right.
My understanding as to the reasoning for the blur event on chrome and firefox is to save resources, but I disagree with that. I feel it should follow the literal interpretation of the command onChange... Sigh... I suppose I'm probably wrong somehow, though.
I would suggest you to write the required code in Key Up event to capture the Key press and and also check for Key Code. Hope this helps
Scrolling through a select box is not considered a change. The change happens when you blur() the select and the new option value is applied to the select element.
Coming back to this, it appears that since the asking of this question, Chrome now fires onChange after key events. Firefox appears to still wait for onblur. http://jsfiddle.net/2aQBN/
$(document).ready(function() {
$("#test").on("change", function() {
console.log("Changed.");
});
});
W3C Specification appears to suggest using an input event instead.
When the input event applies, any time the user causes the element's
value to change, the user agent must queue a task to fire a simple
event that bubbles named input at the input element.
However, no input event appears to fire in Chrome or Firefox for the select element. (Just input elements.)
Test demonstrating the current value vs the last onchange value.
http://jsfiddle.net/teynon/MpyHK/5/
Firefox will change the value onmouseover. The key change will change the value as well. However, the onchange hasn't fired. If the form submits while the user has the select menu open, the currently highlighted option is submitted.
From W3C:
If the multiple attribute is absent, and the element is not disabled,
then the user agent should allow the user to pick an option element in
its list of options that is itself not disabled. Upon this option
element being picked (either through a click, or through unfocusing
the element after changing its value, or through a menu command, or
through any other mechanism), and before the relevant user interaction
event is queued (e.g. before the click event), the user agent must set
the selectedness of the picked option element to true and then queue a
task to fire a simple event that bubbles named change at the select
element, using the user interaction task source as the task source.
There is a LONG discussion at https://bugzilla.mozilla.org/show_bug.cgi?id=126379 about this with many people asking for the arrow keys to work. (And some defending the onchange approach.)
Some users have suggested that the W3C is flat out wrong in the specification for the select element's change event. Instead suggesting we propose changes to the specification for how we expect the select's onchange functionality to work.
The current functionality is clearly not intuitive to a large number of people based solely on the number of bug reports. (Mozilla has 40 marked as duplicates.)
This is a pretty dirty hack, but you can force the the change event to fire by doing this:
element.addEventListener('keyup', function(evt){
evt.target.blur();
evt.target.focus();
}, false);
So you'd register an event listener for change as well, and that function would get called when the user presses a key on the <select> via the code above.
You may want to scope this only to Firefox, but AFAIK you'd have to use UA sniffing for that so it's up to you if that's acceptable.
Source
I'm thinking about something like this (to not trigger event if value wasn't changed):
select.keydown(function(){
var _this = $(this);
var _val = $(this).val();
setTimeout(function(){
if(_this.val() !== _val){
_this.trigger("change");
}
}, 1);
});
Here's a realization of this request. For brevity only showing the code. See https://github.com/ida/skriptz/blob/master/js/fields/select/selection_changed.js for long explanations in comments.
function addSelectionChangedListener(selectionEle, onChangeDoWithEle) {
var selectedIndex = null
function onChangeEvent(eve) {
// If selection-change was caused of an option's click-event:
if(eve.explicitOriginalTarget.tagName.toLowerCase() == 'option') {
// We want to trigger passed event-handler:
onChangeDoWithEle(eve.target)
}
}
function onKeyEvent(eve) {
// Key-event is keydown, remember current selectedIndex:
if(eve.type == 'keydown') {
selectedIndex = eve.target.selectedIndex
}
// Key-event is keyup, if selection changed, trigger passed handler:
else if(selectedIndex != eve.target.selectedIndex) {
onChangeDoWithEle(eve.target)
}
}
selectionEle.onchange = function(eve) onChangeEvent(eve)
selectionEle.onkeydown = function(eve) onKeyEvent(eve)
selectionEle.onkeyup = function(eve) onKeyEvent(eve)
}
I've tried looking for a list of all the possible events that can be used in the a4j:support event attribute. I cant find any reference that lists them, maybe somebody can provide a link?
I'm aware of the obvious ones like onclick, onchange, etc.
The reason I ask this is that I currently have an input text field. It has the onkeyup event attached to it via the a4j:support tag. It should enable a text box when the event fires.
The event does not fire when a user right clicks their mouse and pastes content into the field.
Is there an alternative event I could use to ensure this case is managed?
<h:inputText id="someName" value="#{myBean.example.exampleName}" maxlength="25" style="width:280px">
<a4j:support event="onchange" reRender="exampleTab"
action="#{myBean.activateTabPanel}" ajaxSingle="true"
ignoreDupResponses="true" />
</h:inputText>
<rich:tabPanel id="exampleTab" switchType="server"
style="width:100%;height:448px;" styleClass="top_tab"
inactiveTabClass="inactive_tab" activeTabClass="active_tab"
selectedTab="#{myBean.exampleTabState.selectedTab}">
<!-- Various stuff in here --->
</rich>
## ************ Update ***********##
I actually went with a jQuery solution in the end. Was much cleaner. Code attached for anyone interested.
jQuery(document).ready(function() {
// Call contructor
var common = new Site.Common();
});
// Constructor
Site.Common = function() {
// Only attach event listener if the element exists on page
if ( jQuery('input[id$="suggest"]') ) {
jQuery('input[id$="suggest"]').bind('paste', Site.Common.handleMousePaste.bind(this));
}
};
// Trigger the keyup event when user uses mouse to paste content info a field('element')
Site.Common.handleMousePaste = function(event) {
// Need to split the id (JSF adds the form name in front of the input field!)
var idParts = event.target.id.split(':');
// Reformat the id we will pass to jQuery (It does not understand formName:fieldName, need to escape the ':')
if (idParts.length >= 2) {
var formattedID = "#" + idParts[0] + "\\:" + idParts[1];
}
else {
var formattedID = "#" + event.target.id;
}
// Need to put a tiny delay in so the element has time to get the pasted in content.
setTimeout(function() { jQuery(formattedID).keyup(); }, 10);
};
Thanks
you can detect the paste event in js and activate your function then.
attached is a link that deals with similar problem
link
in it change what happens after the paste is detected
if (event.ctrlKey && event.keyCode == 86) //Paste event
call your function
The keyboard events do not suppose to work when clicking on the mouse (pasting, clicking, etc).
As I understand you searching for a OnChange event but the OnChange is not good for you because
you need that the event will fire in any input that the input text get.
The solution is to use the new HTML5 OnInput Event. The OnInput event fire in any input e.g. past using
the mouse, typing, pasting using the keyboard, etc.
It also support all the new browsers, I test it on: IE9,IE10,IE11,Chrome,Firefox,Safari and Opera.
The list of possible values for the event attribute is not fixed, as explained in the documentation:
Name of JavaScript event property ( onclick, onchange, etc.) of parent component, for which we will build AJAX submission code
So basically, it means that you can set in the event attribute, any onXXX event that is available on the parent component.
Regarding your problem, you can eventually duplicate your <a4j:support event="onkeyup"> with a <a4j:support event="onchange">.
Note that if your request is just to enable a text box, maybe you can do that using JavaScript, and not with Ajax call (i.e. using <a4j:support>).
A widget I'm using modifies an HTML textarea element. I need to know when that element has been modified and preferably I'd like to actually hide that element as well. I'm using jQuery, so I naturally tried the $('#textarea_id').change() event. But it's never triggered because I guess the textarea never loses focus.
What's the best way to monitor that textarea, preferably hidden (CSS has display:none)? Please don't tell me setInterval...
You could manage this with a global variable.
var text = "";
$('#textarea_id').bind("keyup paste", function(e){
if ($(this).val() != text)
{
// text changed
text = $(this).val();
}
});
working example: http://jsfiddle.net/n8keN/
I would use .keyup(). If you don't want the event to fire every keypress, have it restart a half second timer every keypress and have the timer trigger the things you want to happen when the user stops typing. You can play with the time to get it to your liking.