18

Note: Due to a work-related change, I can no longer verify the answers posted here. Most likely, I will never be able to accept an answer down below. The information posted here is useful IMO, so I will just leave it as it is. If you think you know an answer, feel free to answer and we'll just let the community decide which ones are useful.


Background

I am developing a standalone web app for iPod Touch. One of my requirements is to focus on a textfield when a page loads so that a user can do a task continually (e.g. with a barcode reader).

Problem

The problem is that it does focus on the text field in question, but the keyboard does not go up. Is there a workaround for this? Or is this by design by Apple?

Sample Html

I'm unsure on how to put this into a code snippet, but this is where I've been experimenting on:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0.0">

    <meta name="apple-mobile-web-app-capable" content="yes">
    <link rel="apple-touch-icon" href="https://cdn57.androidauthority.net/wp-content/uploads/2016/06/android-win-2-300x162.png">

    <title>TESTING</title>

    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">

    <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

    <script>
        // javascript goes here
    </script>
</head>
<body>

    <section id="content">

        <div class="container" style="margin-top: 50px;" >

            <p>Testing textfield focus</p>

            <form method="POST">
                <div class="row">
                    <div class="col-xs-12">
                        <input type="text" class="form-control first-responder" />
                    </div>
                    <div class="col-xs-12">
                        <button type="submit" class="btn" style="width: 100%" >OK</button>
                    </div>
                </div>
            </form>

        </div>

    </section>

</body>
</html>

I view this on Safari, then add it to the homescreen so that it would act as a standalone web app.

Attempts

I tried searching around for solutions, the first one(I lost the link) suggested to try timeouts like so:

$(function () {
    var firstResponder = $(".first-responder");
    setTimeout(function() {
        firstResponder.focus();

    }, 1000);

})

Another of the solutions I found suggested to set the selection range like so:

$(function () {
    var firstResponder = $(".first-responder");
    setTimeout(function() {
        firstResponder[0].setSelectionRange(0, 9999);

    }, 1000);

})

There was also a suggestion to bind it to a click like so:

$(function () {
    var firstResponder = $(".first-responder");
    firstResponder.on('click', function() {
        firstResponder.focus();
    });

    firstResponder.focus().click();
})

I also tried triggering a touchstart like so:

$(function () {
    var firstResponder = $(".first-responder");
    firstResponder.on('touchstart', function() {
        firstResponder.focus();
    });

    firstResponder.trigger('touchstart');
})

I also tried with a simple ajax call like so (don't mind the success/error. All I wanted to do was focus after ajax call):

function doAjax() {
    var firstResponder = $(".first-responder");

    $.ajax({
        url: "#",
        method: "POST",
        dataType: "json",
        success: function(result) {
            firstResponder.focus();
        },
        error: function(request, error) {
            firstResponder.focus();         
        }
    });
}

I got kind of desperate so I tried setting some css too:

user-select: text;
-webkit-user-select: text;

These solutions worked on iOS 9.1 (except the css one) but all of them failed on iOS 11.1.1. I tried combining various solutions, setting timeouts, etc. but none seem to work. As I noted, it does focus because I can see that the textfield's borders turn blue, signifying that it has focus. But I need to have the keyboard displayed too.

This behavior seems to be either a bug or a usability/security feature. If this is by design (i.e. a security feature), is there an official documentation by Apple that talks about this?

Addendum

If you think that the barcode reader might be the problem, this is not true. In the project I'm working on, the barcode reader replaces the native keyboard. In theory, even without the barcode, as long as I am able to bring up the keyboard on page load, I should be able to fulfill my requirement.

Continuous task is possible because the barcode reader can include an Enter key after the barcode it reads, thereby submitting the form the textfield is on. After the page reloads, if the textfield gets automatically focused, all the user needs to do is read another barcode. The page submits again, reloads, autofocuses, and the cycle can be repeated.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Keale
  • 3,924
  • 3
  • 29
  • 46
  • 1
    Are you using UIWebView or WKWebView to load your homepage. Please refere to this guide:- https://developer.apple.com/documentation/uikit/uiwebview – Jitendra Jan 18 '18 at 08:21
  • No. Sorry, the iOS tag might be misleading, but I'm not programming using Obj-C or Xcode. Rather, I'm developing a standalone web app. Basically html and jQuery. So, no. Not using `UIWebView`. – Keale Jan 18 '18 at 09:31
  • 2
    How I wish to have just been developing on iOS, things might have been a lot simpler. I haven't tried it yet, but I think the solution if developing using Obj-C is to set the [`keyboardDisplayRequiresUserAction`](https://developer.apple.com/documentation/uikit/uiwebview/1617967-keyboarddisplayrequiresuseractio) property of the `UIWebView` to `false` probably via the IB. But one can only dream... – Keale Jan 18 '18 at 09:33
  • 1
    @Keale Are you testing on a real device or on a simulator? – arturdev Jan 19 '18 at 07:54
  • @arturdev on a real device. Two devices in fact. One in iOS 9 and one in iOS 11. I have the devices on hand here, and I just replace the contents of `// javascript goes here` with the solutions suggested here to check. – Keale Jan 19 '18 at 09:14

7 Answers7

5

After some hard on tests I found a way that worked in my girlfriend's iphone 7 with ios 11, now I don't know if it gets to your needs, but it does pop the virtual keyboard!

This is the test html:

<input type='text' id='foo' onclick="this.focus();">
<button id="button">Click here</button>

This is the javascript:

function popKeyboard(input) {
  input.focus();
  input.setSelectionRange(0, 0);
}

$("#button").on("click", function() {
  popKeyboard($("#foo"));
});

And this is the fiddle.

Oh and CanIUse just in case!

Now what this does is when we click the button, this evaluates as User Input, because the keyboard can only be popped up if the user gives input ( in android and ios ), we run the function popKeyboard, which focus the input and sets the selectionRange to 0,0 which means it sets the caret to 0 and the keyboard should pop up.

This was tested in Android and an Iphone 7 with IOS 11.

Be wary that she did warn me that her ios 11 wasn't fully updated, but if it works please do tell me!

danronmoon
  • 3,814
  • 5
  • 34
  • 56
Ivo Silva
  • 367
  • 2
  • 13
  • 1
    Thanks for the insight! I tried this and unfortunately, it didn't work. However I [checked](https://stackoverflow.com/a/1042154/2431281) and found out that for some reason, my devices do not support `setSelectionRange`. (This is the insight I'm talking about). I'll try investigating on why the devices don't support it for now. Thanks a lot! :) – Keale Jan 19 '18 at 10:56
3

Have you try this?

 $(function(){
    $('input.form-control.first-responder').first().focus();
  });

The selector gets narrowed down by first() and ensures that it not affected by other similar classes in the page.

s1mpl3
  • 1,456
  • 1
  • 10
  • 14
3

Have a look at this question w/ solution: jQuery Set Cursor Position in Text Area

If you use the functions described in this solution right after the ajax ready event the keyboard will show up even in Safari on iOS 11.2.2

Florian Chrometz
  • 445
  • 2
  • 9
  • 22
  • I tried the 2 answers, as well as the solution on the question, and it's the same behavior. Worked on iOS 9 but not on iOS 11. Thanks for the suggestion btw :) – Keale Jan 19 '18 at 09:36
2

Use ajaxComplete instead of load or ready event.

I just load 1 file through ajax and ajaxComplete method i have set focus for input field.

This is working example, I hope this will work for you.

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0.0">

    <meta name="apple-mobile-web-app-capable" content="yes">
    <link rel="apple-touch-icon" href="https://cdn57.androidauthority.net/wp-content/uploads/2016/06/android-win-2-300x162.png">

    <title>TESTING</title>

    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">

    <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
 
 <style>
 span{
  display:none;
 }
 </style>
 
    <script>
 $(document).ready(function(){
 
  $("span").load("https://www.w3schools.com/xml/cd_catalog.xml");
 
  $(document).ajaxComplete(function(){
   $(".first-responder")[0].focus();
  });
 });
    </script>
</head>
<body>

    <section id="content">

        <div class="container" style="margin-top: 50px;" >

            <p>Testing textfield focus</p>

            <form method="POST">
                <div class="row">
                    <div class="col-xs-12">
                        <input type="text" class="form-control first-responder" />
                    </div>
                    <div class="col-xs-12">
                        <button type="submit" class="btn" style="width: 100%" >OK</button>
                    </div>
                </div>
            </form>

        </div>

    </section>
<span></span>
</body>
</html>
Tushar Acharekar
  • 880
  • 7
  • 21
  • Thanks for the effort, really. :) But it did not work on iOS 11. It worked on iOS 9 though. – Keale Jan 19 '18 at 09:26
1

if your focusing you need to make sure the browser has completely loaded and not just onDOMContentReady to do this use the standard load event as this fires once loading has completely finished (I.E the render has finished)

Due to some weirdness is modern web kit browsers (chrome, iOS11) a delay has been added for some reason the load event is triggering before the browser is actually completely loaded. however, I make sure to still use the load event as a starting point.

(function($){
  $(function(){
      window.addEventListener("load", function(){
        setTimeout(function(){  $(".first-responder").focus();  }, 150);
      });
  })
})(jQuery);

https://jsfiddle.net/barkermn01/xzua65jd/1/

Barkermn01
  • 6,781
  • 33
  • 83
  • Thanks for the suggestion. I tried it but it doesn't seem to work? I thought it was because you mispelled `function` (I corrected it). But still doesn't seem to work. – Keale Jan 19 '18 at 03:22
  • Fixed typo, and that is rather strange appears to need a delay think load is firing just a little to early updating code to fix it for you now – Barkermn01 Jan 19 '18 at 12:04
1

Just did some more experimenting. In iOS 11, .focus() would not display the keyboard if you tried to set it on the very first control without the user touching a control for the first time. However, .focus() would display the keyboard providing you didn't .blur() on the current document.activeElement before you .focus() on another element.

Below code worked for me from this keypress (barcode reader, ScanBoard) for iPod:-

$(window).keypress(function (e) {
    if (e.which === 13) {
        switch (true) {
            case window.location.href.indexOf('FindReplenishmentLocation') > -1:
            case window.location.href.indexOf('ConfirmReplenishmentLocation') > -1:
            case window.location.href.indexOf('ConfirmReplenishmentPickFace') > -1:
                if (document.activeElement.id === 'pickFaceLocationTextBox' || document.activeElement.id === 'bulkLocationTextBox') {
                    if ($('#skuTextBox').val()) {
                        $('#skuTextBox').focus().select();
                    }
                    else {
                        if (isMobile) {
                            $('#skuTextBox').focus().select();
                        }
                        else {
                            $('#skuTextBox').focus();
                        }
                    }
                }
                else {
                    if (window.location.href.indexOf('ConfirmReplenishmentPickFace') > -1) {
                        if ($('#qtyPutAwayNumericTextBox').val()) {
                            $('#qtyPutAwayNumericTextBox').focus().select();
                        }
                        else {
                            if (isMobile) {
                                $('#qtyPutAwayNumericTextBox').focus().select();
                            }
                            else {
                                $('#qtyPutAwayNumericTextBox').focus();
                            }
                        }
                    }
                    else {
                        $('#next-btn').trigger('click');
                    }
                }
                break;                
            default:
                break;
        }

        e.preventDefault();
    }
});
-4

use becomeFirstResponder() on the webview first