Mobile Safari: Javascript focus() method on inputfield only works with click? - javascript

I have a simple input field like this.
<div class="search">
<input type="text" value="y u no work"/>
</div>​
And I'm trying to focus() it inside a function.
So inside of a random function (doesn't matter what function it is) I have this line …
$('.search').find('input').focus();
This works just fine on every Desktop whatsoever.
However it doesn't work on my iPhone. The field is not getting focused and the keyboard is not shown on my iPhone.
For testing purposes and to show you guys the problem I did a quick sample:
$('#some-test-element').click(function() {
$('.search').find('input').focus(); // works well on my iPhone - Keyboard slides in
});
setTimeout(function() {
//alert('test'); //works
$('.search').find('input').focus(); // doesn't work on my iPhone - works on Desktop
}, 5000);​
Any idea why the focus() wouldn't work with the timeout function on my iPhone.
To see the live example, test this fiddle on your iPhone. http://jsfiddle.net/Hc4sT/
Update:
I created the exact same case as I'm currently facing in my current project.
I have a select-box that should — when "changed" — set the focus to the input field and slide-in the kexboard on the iphone or other mobile devices. I found out that the focus() is set correctly but the keyboard doesn't show up. I need the keyboard to show up.

Actually, guys, there is a way. I struggled mightily to figure this out for [LINK REMOVED] (try it on an iPhone or iPad).
Basically, Safari on touchscreen devices is stingy when it comes to focus()ing textboxes. Even some desktop browsers do better if you do click().focus(). But the designers of Safari on touchscreen devices realized it's annoying to users when the keyboard keeps coming up, so they made the focus appear only on the following conditions:
1) The user clicked somewhere and focus() was called while executing the click event. If you are doing an AJAX call, then you must do it synchronously, such as with the deprecated (but still available) $.ajax({async:false}) option in jQuery.
2) Furthermore -- and this one kept me busy for a while -- focus() still doesn't seem to work if some other textbox is focused at the time. I had a "Go" button which did the AJAX, so I tried blurring the textbox on the touchstart event of the Go button, but that just made the keyboard disappear and moved the viewport before I had a chance to complete the click on the Go button. Finally I tried blurring the textbox on the touchend event of the Go button, and this worked like a charm!
When you put #1 and #2 together, you get a magical result that will set your login forms apart from all the crappy web login forms, by placing the focus in your password fields, and make them feel more native. Enjoy! :)

A native javascript implementation of WunderBart's answer.
function onClick() {
// create invisible dummy input to receive the focus first
const fakeInput = document.createElement('input')
fakeInput.setAttribute('type', 'text')
fakeInput.style.position = 'absolute'
fakeInput.style.opacity = 0
fakeInput.style.height = 0
fakeInput.style.fontSize = '16px' // disable auto zoom
// you may need to append to another element depending on the browser's auto
// zoom/scroll behavior
document.body.prepend(fakeInput)
// focus so that subsequent async focus will work
fakeInput.focus()
setTimeout(() => {
// now we can focus on the target input
targetInput.focus()
// cleanup
fakeInput.remove()
}, 1000)
}
Other References: Disable Auto Zoom in Input "Text" tag - Safari on iPhone

I faced the same issue recently. I found a solution that apparently works for all devices. You can't do async focus programmatically but you can switch focus to your target input when some other input is already focused. So what you need to do is create, hide, append to DOM & focus a fake input on trigger event and, when the async action completes, just call focus again on the target input. Here's an example snippet - run it on your mobile.
edit:
Here's a fiddle with the same code. Apparently you can't run attached snippets on mobiles (or I'm doing something wrong).
var $triggerCheckbox = $("#trigger-checkbox");
var $targetInput = $("#target-input");
// Create fake & invisible input
var $fakeInput = $("<input type='text' />")
.css({
position: "absolute",
width: $targetInput.outerWidth(), // zoom properly (iOS)
height: 0, // hide cursor (font-size: 0 will zoom to quarks level) (iOS)
opacity: 0, // make input transparent :]
});
var delay = 2000; // That's crazy long, but good as an example
$triggerCheckbox.on("change", function(event) {
// Disable input when unchecking trigger checkbox (presentational purpose)
if (!event.target.checked) {
return $targetInput
.attr("disabled", true)
.attr("placeholder", "I'm disabled");
}
// Prepend to target input container and focus fake input
$fakeInput.prependTo("#container").focus();
// Update placeholder (presentational purpose)
$targetInput.attr("placeholder", "Wait for it...");
// setTimeout, fetch or any async action will work
setTimeout(function() {
// Shift focus to target input
$targetInput
.attr("disabled", false)
.attr("placeholder", "I'm alive!")
.focus();
// Remove fake input - no need to keep it in DOM
$fakeInput.remove();
}, delay);
});
label {
display: block;
margin-top: 20px;
}
input {
box-sizing: border-box;
font-size: inherit;
}
#container {
position: relative;
}
#target-input {
width: 250px;
padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="container">
<input type="text" id="target-input" placeholder="I'm disabled" />
<label>
<input type="checkbox" id="trigger-checkbox" />
focus with setTimetout
</label>
</div>

This solution works well, I tested on my phone:
document.body.ontouchend = function() { document.querySelector('[name="name"]').focus(); };
enjoy

I have a search form with an icon that clears the text when clicked. However, the problem (on mobile & tablets) was that the keyboard would collapse/hide, as the click event removed focus was removed from the input.
Goal: after clearing the search form (clicking/tapping on x-icon) keep the keyboard visible!
To accomplish this, apply stopPropagation() on the event like so:
function clear ($event) {
$event.preventDefault();
$event.stopPropagation();
self.query = '';
$timeout(function () {
document.getElementById('sidebar-search').focus();
}, 1);
}
And the HTML form:
<form ng-controller="SearchController as search"
ng-submit="search.submit($event)">
<input type="search" id="sidebar-search"
ng-model="search.query">
<span class="glyphicon glyphicon-remove-circle"
ng-click="search.clear($event)">
</span>
</form>

I managed to make it work with the following code:
event.preventDefault();
timeout(function () {
$inputToFocus.focus();
}, 500);
I'm using AngularJS so I have created a directive which solved my problem:
Directive:
angular.module('directivesModule').directive('focusOnClear', [
'$timeout',
function (timeout) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var id = attrs.focusOnClear;
var $inputSearchElement = $(element).parent().find('#' + id);
element.on('click', function (event) {
event.preventDefault();
timeout(function () {
$inputSearchElement.focus();
}, 500);
});
}
};
}
]);
How to use the directive:
<div>
<input type="search" id="search">
<i class="icon-clear" ng-click="clearSearchTerm()" focus-on-clear="search"></i>
</div>
It looks like you are using jQuery, so I don't know if the directive is any help.

UPDATE
I also tried this, but to no avail:
$(document).ready(function() {
$('body :not(.wr-dropdown)').bind("click", function(e) {
$('.test').focus();
})
$('.wr-dropdown').on('change', function(e) {
if ($(".wr-dropdow option[value='/search']")) {
setTimeout(function(e) {
$('body :not(.wr-dropdown)').trigger("click");
},3000)
}
});
});
I am confused as to why you say this isn't working because your JSFiddle is working just fine, but here is my suggestion anyway...
Try this line of code in your SetTimeOut function on your click event:
document.myInput.focus();
myInput correlates to the name attribute of the input tag.
<input name="myInput">
And use this code to blur the field:
document.activeElement.blur();

Try this:
input.focus();
input.scrollIntoView()

Please try using on-tap instead of ng-click event. I had this issue. I resolved it by making my clear-search-box button inside search form label and replaced ng-click of clear-button by on-tap. It works fine now.

Related

JQuery is not triggering atbar button

I am working on a large project and need to fix some accessibility issues.
These is a section which has been generated by https://www.atbar.org/ in a JS format I am not familiar with. The user clicks buttons to change font size, background colour and other html elements to assist them with reading content.
When you click on the buttons with your mouse they work fine. This is an example of how the buttons appear:
<li class=“access-button">
<a title="Decrease Text Size" id="block_accessibility_dec" tabindex=“0">A-</a>
</li>
If I focus my Chrome inspector on the link element I can see there is an event listening for my click:
This appears to trigger the change in font size. I found the code that triggers this click, it is in a JS format that I am not familiar with:
M.block_accessibility = {
init: function(Y, autoload_atbar, instance_id) {
this.defaultsize = M.block_accessibility.DEFAULT_FONTSIZE;
// This event triggers after clicking
Y.all('#block_accessibility_textresize a').on('click', function(e) {
if (!e.target.hasClass('disabled')) {
M.block_accessibility.changesize(e.target);
}
});
// This is the function it runs, it has many cases for all the different buttons.
changesize: function(button) {
Y = this.Y;
switch (button.get('id')) {
case "block_accessibility_dec":
Obviously this is just snippets of the code with comments I added.
What I require is the user to be able to change the font size using just tab and enter, so I added the following JQuery:
$("#block_accessibility_dec").keyup(function(event) {
if (event.keyCode === 13) {
$('#block_accessibility_textresize #block_accessibility_dec').click();
}
});
This is not triggering the change in font size. Yet when I click on the button it does? There is probably a really simple solution here but I've been stuck for ages. I tested the .click() on other elements on the screen and it works for them so the JS is definitely executing.
I have also tested:
$(this).click();
But to no avail.
Try to trigger the click event by the native way:
$('#block_accessibility_textresize #block_accessibility_dec')[0].click();
Source: I tried their demo page together with the chrome inspector and couldn't get the click working with JQuery.
But with the native click event it suddenly worked.
Unfortunately I can't really explain to you, why JQuery doesn't work here. Maybe something with their version (1.11)?
Replace your code with the following code and add the keyup event. This should work when you press the enter key.
Y.all('#block_accessibility_textresize a').on('click keyup', function(e) {
if (e.keyCode == 13 || e.keyCode ==9) {
if (!e.target.hasClass('disabled')) {
M.block_accessibility.changesize(e.target);
}
}
});
You should use the following Jquery:
$('#block_accessibility_textresize #block_accessibility_dec').trigger("click");
Please let me know if this doesn't work.

Auto Show Soft Keyboard on mobile web browser

I want to make the soft keyboard show on
$( document ).ready(function() {
....
});
here's my html code:
<form id="typerForm">
<input id="typer" style="position:relative; left:-100em;"/>
</form>
<div id="myInput" style="border:2px solid #4AA; width:6em; height:1em; font-size:2em"></div>
<div style="height:20em; background-color:#eee">
</div>
and here's my javascript code:
$('body').click(function() {
$('#typer').focus();
$('#typer').select();
});
$('#typerForm').submit(function() {
//alert("submit");
setTimeout("$('#typer').focus();", 1000);
return false;
});
$('#typer').bind('keyup', function(e) {
var input = $.trim($(this).val());
// some lines of code..
$('#myInput').text(input);
//...
//$(this).val('').focus(); // clean up
});
or you can look at my code here http://jsfiddle.net/7urry794/
my code works to show the keyboard on mobile web browser when i click on somewhere or click on the input text. And what i want is show keyboard automatically when the page ready or finish loading
you can use below code to open keyboard on iOS or Android
There are a couple of ways I know of to get around this:
prompt() opens the keyboard
If you trigger the .focus() from within a .click() event (e.g. from opening your dialog), the keyboard shows up
Hope it might help
You can do this by calling focus() then click() on the input, but only if the script is initiated by user input. All attempts to get this to work from an onload handler with no user interaction FAILED :-( Beware of endless loops if your script is triggered by an onclick() on a containing element. The script below is working for me on Chrome for android 58 and Safari mobile 602.1, when called from an onclick().
function onSomethingOtherThanLoad(event){
// get the input
var target = document.getElementsByTagName("input")[0];
if (event.target != target) {
target.focus();
target.click();
}
}

ng-blur don't fire event on firefox with input number

I am trying to use ng-blur with an html input (type=number) element on firefox.
The problem I found is that when using the up and down arrows of the input number neither the blur nor the focus events are fired with firefox whereas with chrome works fine.
You can reproduce the issue in http://jsfiddle.net/chonw54e/
<div ng-app ng-init="focus=false;blur=false;active=false">
<input type="number" ng-class="{ myFocus: focus, myBlur: blur }" ng-focus="focus=true;blur=false;" ng-blur="blur=true;focus=false;">
<p>focus: {{focus}}</p>
<p>blur: {{blur}} </p>
</div>
Just load the page (with both firefox and chrome) and click on the up/down arrows of the html input number
input number
What am I doing wrong?
Thanks for the help!
EDIT: 11/12/2015
#Arg0n's solution fix the problem. However, it looks like a problem of either firefox or angularjs.
I have just created an issue on angular github here
It is not an angular problem. It is due to the firefox's event behaviour which don't focus the input when clicking the arrows inside the input (which in my opinion is a mistake).
EDIT: 14/12/2015
Firefox Issue created in bugzilla: https://bugzilla.mozilla.org/show_bug.cgi?id=1232233
You can fix this with jQuery, see this fiddle:
JavaScript
$(function(){
$("input[type='number']").on("click", function(){
$(this).focus();
});
});
Without jQuery, see this:
JavaScript
document.onreadystatechange = function() {
if (document.readyState == "complete") {
var inputs = document.querySelectorAll('[type="number"]');
for (var i = 0; i < inputs.length; i++) {
inputs[i].onclick = function() {
this.focus();
}
}
}
}
This will force the browser to focus on the input when it's clicked. (Input with type set to number).
A simple onclick="this.focus();" will work as nicely and much simpler if you have one field or using Angularjs's ng-repeat.

How to call a function when default browser autocomplete list item selected [duplicate]

I have a pretty simple form. When the user types in an input field, I want to update what they've typed somewhere else on the page. This all works fine. I've bound the update to the keyup, change and click events.
The only problem is if you select an input from the browser's autocomplete box, it does not update. Is there any event that triggers when you select from autocomplete (it's apparently neither change nor click). Note that if you select from the autocomplete box and the blur the input field, the update will be triggered. I would like for it to be triggered as soon as the autocomplete .
See: http://jsfiddle.net/pYKKp/ (hopefully you have filled out a lot of forms in the past with an input named "email").
HTML:
<input name="email" />
<div id="whatever"><whatever></div>
CSS:
div {
float: right;
}
Script:
$("input").on('keyup change click', function () {
var v = $(this).val();
if (v) {
$("#whatever").text(v);
}
else {
$("#whatever").text('<whatever>');
}
});
I recommending using monitorEvents. It's a function provide by the javascript console in both web inspector and firebug that prints out all events that are generated by an element. Here's an example of how you'd use it:
monitorEvents($("input")[0]);
In your case, both Firefox and Opera generate an input event when the user selects an item from the autocomplete drop down. In IE7-8 a change event is produced after the user changes focus. The latest Chrome does generate a similar event.
A detailed browser compatibility chart can be found here:
https://developer.mozilla.org/en-US/docs/Web/Events/input
Here is an awesome solution.
$('html').bind('input', function() {
alert('test');
});
I tested with Chrome and Firefox and it will also work for other browsers.
I have tried a lot of events with many elements but only this is triggered when you select from autocomplete.
Hope it will save some one's time.
Add "blur". works in all browsers!
$("input").on('blur keyup change click', function () {
As Xavi explained, there's no a solution 100% cross-browser for that, so I created a trick on my own for that (5 steps to go on):
1. I need a couple of new arrays:
window.timeouts = new Array();
window.memo_values = new Array();
2. on focus on the input text I want to trigger (in your case "email", in my example "name") I set an Interval, for example using jQuery (not needed thought):
jQuery('#name').focus(function ()
{
var id = jQuery(this).attr('id');
window.timeouts[id] = setInterval('onChangeValue.call(document.getElementById("'+ id +'"), doSomething)', 500);
});
3. on blur I remove the interval: (always using jQuery not needed thought), and I verify if the value changed
jQuery('#name').blur(function ()
{
var id = jQuery(this).attr('id');
onChangeValue.call(document.getElementById(id), doSomething);
clearInterval(window.timeouts[id]);
delete window.timeouts[id];
});
4. Now, the main function which check changes is the following
function onChangeValue(callback)
{
if (window.memo_values[this.id] != this.value)
{
window.memo_values[this.id] = this.value;
if (callback instanceof Function)
{
callback.call(this);
}
else
{
eval( callback );
}
}
}
Important note: you can use "this" inside the above function, referring to your triggered input HTML element. An id must be specified in order to that function to work, and you can pass a function, or a function name or a string of command as a callback.
5. Finally you can do something when the input value is changed, even when a value is selected from a autocomplete dropdown list
function doSomething()
{
alert('got you! '+this.value);
}
Important note: again you use "this" inside the above function referring to the your triggered input HTML element.
WORKING FIDDLE!!!
I know it sounds complicated, but it isn't.
I prepared a working fiddle for you, the input to change is named "name" so if you ever entered your name in an online form you might have an autocomplete dropdown list of your browser to test.
Detecting autocomplete on form input with jQuery OR JAVASCRIPT
Using: Event input. To select (input or textarea) value suggestions
FOR EXAMPLE FOR JQUERY:
$(input).on('input', function() {
alert("Number selected ");
});
FOR EXAMPLE FOR JAVASCRIPT:
<input type="text" onInput="affiche(document.getElementById('something').text)" name="Somthing" />
This start ajax query ...
The only sure way is to use an interval.
Luca's answer is too complicated for me, so I created my own short version which hopefully will help someone (maybe even me from the future):
$input.on( 'focus', function(){
var intervalDuration = 1000, // ms
interval = setInterval( function(){
// do your tests here
// ..................
// when element loses focus, we stop checking:
if( ! $input.is( ':focus' ) ) clearInterval( interval );
}, intervalDuration );
} );
Tested on Chrome, Mozilla and even IE.
I've realised via monitorEvents that at least in Chrome the keyup event is fired before the autocomplete input event. On a normal keyboard input the sequence is keydown input keyup, so after the input.
What i did is then:
let myFun = ()=>{ ..do Something };
input.addEventListener('change', myFun );
//fallback in case change is not fired on autocomplete
let _k = null;
input.addEventListener( 'keydown', (e)=>_k=e.type );
input.addEventListener( 'keyup', (e)=>_k=e.type );
input.addEventListener( 'input', (e)=>{ if(_k === 'keyup') myFun();})
Needs to be checked with other browser, but that might be a way without intervals.
I don't think you need an event for this: this happens only once, and there is no good browser-wide support for this, as shown by #xavi 's answer.
Just add a function after loading the body that checks the fields once for any changes in the default value, or if it's just a matter of copying a certain value to another place, just copy it to make sure it is initialized properly.

After clicking on selected text, window selection is not giving updated range

After double click, selection range can be obtained correctly on onclick event but when I again click on the selected text then updated selection range should be returned by window selection but this is not happening. Can anybody tell me if this is a bug in javascript selection or they have made it this way. And what could be the solution to get the updated range apart from timer.
<div id="xyz" contenteditable="true">Hello world</div>
<span class="status">Selected text : </span>
javascript code :
function yourFunction() {
if (window.getSelection) {
var selectionRange = window.getSelection();
$('.status').text(selectionRange.toString());
}
}
$('#xyz').click(function () {
$('.status').text('Mouse click');
yourFunction();
})
Example here
You fiddle is working just fine. But, yes sometimes when you do selections in quick succession, then it fails to register the click.
The problem really lies in the way you have implemented it on click on the text input itself. A click event is generated when a mouseup follows a mousedown. A selection happens when you mousedown then drag and then mouseup.
If you separate out the selection retrieval then this problem won't occur.
See this updated fiddle: http://jsfiddle.net/zRr4s/21/
Here, the selection retrieval is donw on a button click, instead of the input itself.
i.e., instead of:
$('#xyz').click(function (e) { ...
using this:
$('#btn').click(function () { ...
where, btn is:
<input id="btn" type="button" value="get selection" />
Hope that helps.
Update:
If you insist on handling event only on the input, then listening mouseup would be better option:
See this fiddle: http://jsfiddle.net/zRr4s/22/
$('#xyz').on("mouseup", function (e) { ...
Update 2:
To handle your requirement of in-context click, you will have to first clear the selection. For this to happen you will have to handle mousedown. So, that will defeat your purpose of having only one handler. Anyway,
You updated fiddle: http://jsfiddle.net/zRr4s/29/
And, this is how you do it:
$('#xyz').on("mousedown", function () {
clearTheSelection();
});
Where clearTheSelection is another function:
function clearTheSelection() {
if (window.getSelection) {
if (window.getSelection().empty) { // Chrome
window.getSelection().empty();
} else if (window.getSelection().removeAllRanges) { // Firefox
window.getSelection().removeAllRanges();
}
} else if (document.selection) { // IE?
document.selection.empty();
}
}
The complete code for the above function taken from this answer: https://stackoverflow.com/a/3169849/1355315
Hope that completes all your problems.
The fiddle provided in the question works fine in Edge and IE11 but doesn't work in Chrome. I found a trick to make it work everywhere. Add the following event handler in addition to the click handler you already have:
$(document).on("selectionchange", function () {
yourFunction();
});
Some notes:
selectionchange is a document level event, you cannot bind it to specific element (but you can find out whether you need to handle it within the event handler)
Handling selectionchange without also handling click doesn't work well in Edge and IE11
According to MDN, browser support is good enough: https://developer.mozilla.org/en-US/docs/Web/API/Document/selectionchange_event

Categories

Resources