I have a javascript function that uses the onkeyup and onchange events to update some texts when the user changes the value of some input boxes. The update function works on the client side.
It works well on most browsers, including Chrome for Windows, but in Chrome for and Android pressing the backspace key doesn't fire the onkeyup event.
The onchange works well when the focus moves to another input, but it is not intuitive. The onchange event on the form also fires when the focus changes.
I don't like this:
The user types a few characters -> the feedback is shown in real time (good)
The user types the wrong character -> an error message is shown (good)
The user presses backspace to remove the wrong character -> the error message is still there (BAD)
Any idea on how to get the update in real time after pressing backspace in all the browsers?
You can use the DOM input event that is fired synchronously when the value of an <input> or <textarea> element is changed.
According to the Mozilla developer documentation there is basic support for this in all mobile and desktop browsers including Internet Explorer from version 9. Mozilla developer documentation for Input Event
At the moment as far as I can tell no browser provides any information yet regarding what has changed in the <input> element however this shouldn't affect your solution.
Related
I am trying to add an EventListener on the body tag, which works fine on Chrome, but not on Internet Explorer (Edge). See code below. However, it works in IE, but only after I select an input textbox. But I don't want to select an input textbox first, the EventListener should listen immediately after I load the page.. What am I doing wrong here?
document.getElementsByTagName('body')[0].addEventListener('paste', function() {
console.log('hi');
});
This is a known limitation of Internet Explorer. It:
Only fires copy event on a valid selection and only cut and paste in focused editable fields.
You are doing nothing wrong.
Since you haven't focused an element (e.g. with autofocus), no editable field will have the focus just after the document has loaded.
Keep in mind that IE11 is not a browser under active development. It continues to exist primarily for compatibility with ancient Intranet applications. Not with modern web applications.
I have built a website that uses some simple JavaScript. I make use of many events throughout the website such as the input and submit event for validating and processing a contact form, the focus event for some form-related things and a dynamically-created tab interface, etc. I register all of these handlers using element.addEventListener("event", handler).
My JavaScript works wonderfully everywhere that I have been able to test (Firefox and Chrome on Ubuntu; Firefox and Chrome on Android), except for on iOS devices (regardless of what browser is used), where it seems that very few events are being fired.
It has been difficult for me to debug what the issue is on iOS devices because I do not have an OSX computer to connect an iOS device to so that I can use the remote console. I have come to the conclusion that the events are not firing for a few reasons:
The contact form on the website is being submitted even though I make a call to event.preventDefault() in the form's submit event handler, and do not explicitly submit the form anywhere after that.
I have tried catching any errors and displaying them in an alert like so:
window.onerror(function(err) { alert(err) })
to no avail (i.e. no errors were caught).
I have adapted all my functions to make use of only the click event, and then they work perfectly!
The last point is a possible solution to the problem, but I think it is bad practice to adapt all my work to one specific platform and rely only on a single event when there are so many purpose-built events that can be used and that are supposedly supported by iOS in the first place.
Why are so many events not being fired on iOS devices?
The problem was actually that I had made a const declaration in strict mode, which is, according to caniuse, not recognized in the current versions of both Safari and iOS Safari (9.1 and 9.3, respectively, as of writing).
I have better documented this problem in another question and answer.
Prior to iOS8, using the Javascript .focus() method on an input element would appear to have no effect (the virtual keyboard would not display). After the latest iOS 8 release, running the .focus() method seemed to have no effect on page load but once a user touched anywhere on the screen the virtual keyboard would instantly appear and scroll the page to the element in focus. (This is also an issue when I use the HTML attribute "autofocus")
This change has caused issues with iOS8 users on my site. When a user attempts to click a button on my page the sudden scroll and keyboard appearance causes them to unintentionally click a button that was lower on the screen.
I am assuming this is a bug in iOS8 and was not intentional feature, my question is what is the most efficient solution to fixing this problem?
Do I have to check navigator.userAgent to see if the device is iOS8, every time I use the .focus() method?
It looks like you're definitely hitting an iOS 8 bug. In iOS7, Safari would (apparently) ignore or keep unfocused elements that had focus set prior to page load. This includes both <input autofocus> and input.focus() that occur up to some point, possibly page load (I tested just with an inline script).
In iOS 8, Safari is now apparently remembering that the element was focussed but not actually focussing it until a touch down event. It is then blindly sending a click event to whichever element received the touch up.
Both browsers behave the same for input.focus() occurring after page load. They both zoom to the element and bring up the keyboard.
Tests:
input.focus() before page load: http://fiddle.jshell.net/qo6ctnLz/3/show/
<input autofocus>: http://fiddle.jshell.net/qo6ctnLz/4/show/
input.focus() after page load: http://fiddle.jshell.net/qo6ctnLz/6/show/
The good news is that you only need to be worried about new behavior on elements you want to prefocus. The other good news is that while you will have to use a user-agent workaround, you can use it for all iOS versions since they were already behaving like you weren't autofocusing:
if (!/iPad|iPhone|iPod/g.test(navigator.userAgent)) {
element.focus();
}
This appears to be the approach http://www.google.com uses based on some basic user-agent testing:
Mac Book Pro: autofocus before page load.
iPhone: no autofocus
iPad: no autofocus
Kit Kat (Android): focus after page load, possibly doing extra detection for presence of software keyboard.
If you haven't, you should go ahead and file a radar with Apple at https://bugreport.apple.com.
If you are developing a Cordova project, you can fix it adding this line
<preference name="KeyboardDisplayRequiresUserAction" value="false" />
to your config.xml file. Tested in IOS 8.3 and IOS 8.4
It seems that in iOS 8 there has been an API change on the default handling for the javascript focus() command. If your application is a hybrid app in which you have direct control over Apple's web view facade the below is directly from apples docs.
A Boolean value indicating whether web content can programmatically
display the keyboard.
[myWebView setKeyboardDisplayRequiresUserAction:YES];
When this property is set to YES, the user must explicitly tap the
elements in the web view to display the keyboard (or other relevant
input view) for that element. When set to NO, a focus event on an
element causes the input view to be displayed and associated with that
element automatically.
The default value for this property is YES.
From the last paragraph it seems this method call is not strictly for the keyboard. It indicates that it is for input views across the board i.e. drop down and date picker etc.
It seems though there is a bug as this method call is not currently working for me. The current behavior I am receiving corresponds as if it defaults to NO.
I have a solution:
Disable all inputs
Enable the input you wish to focus
Set the focus to that input
Re-enable all the other inputs
Here's a conditional monkeypatch for jQuery.focus so you don't need to add the userAgent test everywhere.
JavaScript
if (/iPad|iPhone|iPod/g.test(navigator.userAgent)) {
(function($) {
return $.fn.focus = function() {
return arguments[0];
};
})(jQuery);
}
CoffeeScript
if /iPad|iPhone|iPod/g.test navigator.userAgent
(($) ->
$.fn.focus = ->
arguments[0]
)(jQuery)
Note: I'm returning arguments[0] so we don't break method chaining such as $(el).focus().doSomethingElse()
I've logged a bug about this into the Apple Bug Reporter and they closed it as duplicate, which is a sign they are working on fixing this. Unfortunately they didn't give me some more information about the duplicate item or about the problem itself. I can only see the duplicate item state, which is Open.
For anyone coming to this on 2018, there is a plugin that fix it. Just install this https://github.com/onderceylan/cordova-plugin-wkwebview-inputfocusfix and input.focus() will work automatically without any additional work.
I want to do something when the escape key is pressed by the user on a text field. This code logs 27 whenever the escape key is pressed in the input box in Safari and Firefox, but not in Chrome. I also tried binding to keyup, not using jQuery (i.e., just using raw JavaScript), and tried using keyCode instead of which, none of which helped. Incidentally, Chrome seems to do just fine with all other keys like Enter, the modifier keys, etc. Any idea what's up?
NB: I'm using Chrome 22.0.1229.94 on Mountain Lion.
UPDATE: By the way, if it helps, when I press escape on the input box in Chrome, it loses focus while on the other two browsers it does not.
Finally found what was causing this: the Vimium chrome extension, which catches the Escape key.
A bug has been filed for it here: https://github.com/philc/vimium/issues/499.
I've noticed a strange issue with how Chrome handles javascript focus event. The fact is, it continuosly triggers focus event, even if it occurs only once. I've made a bit of research here and found questions where people run into the same issue when using alert(). When they close the alert window, the focus returns to their inputs and a handler triggers again and again. In my case, the problem is different, as I am using console.log(), and from time to time I get the same log 2 or even 3 times. I've noticed it usually happens when I clear the console, and then focus on an element. When I try to repeat it, it does not occur any more.
The scenario:
Clear console
Focus on element (2 or 3 console messages)
Focus on other identical element or unfocus and focus again on the
same one (no problems)
Clear console
Focus on element (2 or 3 console messages - the problem is back!)
I've created a jsfiddle, please check it out:
http://jsfiddle.net/ffuWT/3/
The question is, what is the reason for this issue and how can I work around it?
Creepy how these things can happen. I've run into this exact issue at work today, but have quickly written this off suspecting dodgy event listening and propagation in a 3rd-party plugin (jQuery customInput). I'll double-check your jsfiddle tomorrow.
I'm unable to recreate your exact output on my currently available setup (Chrome v17 on a Mac) but I do have a theory to share. In your scenario and in Ben Lee's comment the consistent part is shifting focus to another window (console in your case).
Check out http://www.quirksmode.org/dom/events/blurfocus.html under "Window + focusable element":
If the window is sent backward while a focusable element is focused,
blur events should fire on both. If the window is brought forward
again, focus events should fire on both.
And next, in the compatibility table it's noted that
Safari Windows fires two focus events.
Maybe Chrome finally got this "feature" too, coming from the Webkit family and all?
I was able to recreate the problem (using your jsFiddle) and from what I can see it only occurs when you click the select without having focus on/in the result frame.
Click within the frame but not on the selects before you click to expand one of the selects and you´ll only see one line logged.
You can also append /show to the jsFiddle URL to view the result in a separate window.
It seems like focusing the window by clicking on a select control triggers the event multiple times.
Open this demo and unfocus the browser window (by clicking the desktop, taskbar or another window) and then click on one of the selects to expand its options and view the console.
Using Chrome 17.0.963.79 m.