18

Is there a possiblity to force an iOS-device to show the numeric keyboard while using a custom pattern as input type?

my input pattern:

<input id="price" class="numeric" pattern="\d+((\.|,)\d{1,2})?" name="price" 
title="" data-mini="true" data-clear-btn="true" autocomplete="off" autofocus />

I want to type a currency value like '14.99' and show up a keyboard with access to numbers on the iOS device

<input type='number' />
<input pattern='[0-9]*' />
<input pattern='[\d]*' />

are all missing the decimal sign and/or are not validating as number when adding a decimal sign. An alternative way could be a javascript function which is creating the decimal sign on the right place, like pressing 1->2->9->9 in this order creates on keypress() 0.01->0.12->1.29->12.99, but this requires the input field to be type='text' --> obvious problem here is that the text keyboard is showed when focussing the input field.

How can I solve this issue?

EDIT

Environment:

  • JQM 1.3.2
  • jquery 1.8.2
Community
  • 1
  • 1
tronc
  • 683
  • 4
  • 12
  • 23

4 Answers4

21

For now, JavaScript is the only solution. Here's the simplest way to do it (using jQuery):

HTML

<input type="text">

JavaScript

$('input[type="text"]').on('touchstart', function() {
  $(this).attr('type', 'number');
});

$('input[type="text"]').on('keydown blur', function() {
  $(this).attr('type', 'text');
});

The idea is simple. The input starts off and ends up with type="text", but it briefly becomes type="number" on the touchstart event. This causes the correct iOS keyboard to appear. As soon as the user begins to enter any input or leave the field, the input becomes type="text" once again, thus circumventing the validation.

There's one downside to this method. When the user returns to an input that has already been filled out, the input will be lost (if it doesn't validate). This means the user won't be able to go back and edit previous fields. In my case, this isn't all that bad because the user may want to use the calculator over and over again with different values, so automatically deleting the input will save them a few steps. However, this may not be ideal in all cases.

It looks like Mobile Safari supports the new HTML5 input type attributes of email, number, search, tel, and url. These will switch the keyboard that is displayed. See the type attribute.

So for example, you could do this:

<input type="number" />

And when the input box has focus, the number keyboard is shown (as if the user had the full keyboard and hit the "123" button.

If you really only want numbers, you could specify:

<input type="tel" />

And then the user would get the phone number dialing keypad.

I know this works with Mobile Safari -- I only assume it will work with UIWebView.

http://conecode.com/news/2011/12/mobile-safari-uiwebview-input-types/

Omar
  • 32,302
  • 9
  • 69
  • 112
Vizllx
  • 9,135
  • 1
  • 41
  • 79
  • I think this solutions is the simplest approach for this particular problem. thanks! – tronc Nov 20 '13 at 16:27
  • I think you meant to put the second event listener on input's with `[type="number"]` – Justus Romijn Aug 08 '14 at 11:05
  • 1
    Be very very careful: 1. iPhone and iPad can act differently (e.g. type=text pattern="[0-9]*" works wonderfully on iPad but shows numeric only keyboard on iPhone) 2. I think your solution is broken in iOS8, and 3. Sometimes on-screen the input shows you have entered something, but input.value returns blank. 4. I tried using timeouts, but even with a 0ms timeout, the user can quickly type in something before your timeout fires (on a iPhone 4 which is slower). – robocat Oct 21 '14 at 06:10
  • This seems to work on an iphone but it does not work on an android phone.. first time you hit a number the keyboard goes away and the number is not entered. Any idea how to work around this? – Greywire Jul 27 '15 at 18:21
  • 2
    This solution is buggy in Android, each of the keydown events seems to drop the keyboard down. If I find a solution will post it here – jsmartfo Aug 27 '15 at 22:18
  • I will be glad to help you with the android solution, but the solution works perfectly in Safari browser, if I find a way through to fix it..I will edit the Answer soon. @jsmartfo – Vizllx Aug 28 '15 at 06:01
9

I made this little snippet to achieve what you want and I've tested it on iPhone 5 v7.0.3

I used e.which to read CharCode entered and then push it into an array (before) which represents digits before decimal mark and another array (after) to move values from (before) array past the decimal mark.

It might look complicated, due to my humble programming skills.

1) Code demo - 2) Currency conversion demo

HTML:

<input type="tel" id="number" />

JS

Variables and functions:

// declare variables
var i = 0,
    before = [],
    after = [],
    value = [],
    number = '';

// reset all values
function resetVal() {
    i = 0;
    before = [];
    after = [];
    value = [];
    number = '';
    $("#number").val("");
    $(".amount").html("");
}

// add thousand separater
function addComma(num) {
  return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}

Main code:

// listen to keyup event
$("#number").on("keyup", function (e, v) {

    // accept numbers only (0-9)
    if ((e.which >= 48) && (e.which <= 57)) {

        // convert CharCode into a number   
        number = String.fromCharCode(e.which);

        // hide value in input
        $(this).val("");

        // main array which holds all numbers
        value.push(number);

        // array of numbers before decimal mark
        before.push(value[i]);

        // move numbers past decimal mark
        if (i > 1) {
            after.push(value[i - 2]);
            before.splice(0, 1);
        }

        // final value
        var val_final = after.join("") + "." + before.join("");

        // show value separated by comma(s)
        $(this).val(addComma(val_final));

        // update counter
        i++;

        // for demo
        $(".amount").html(" " + $(this).val());

    } else {

        // reset values
        resetVal();
    }
});

Reset:

// clear arrays once clear btn is pressed
$(".ui-input-text .ui-input-clear").on("click", function () {
    resetVal();
});

Result:

enter image description here

Omar
  • 32,302
  • 9
  • 69
  • 112
  • many many thanks for your effort, but after testing both solutions, the answer from Vizllx fits my customer needs more. this one's look and feel was discussed but not accepted by the decision-makers ;) still voted up for your effort. – tronc Nov 20 '13 at 16:31
  • 1
    @tronc you're welcome. I enjoyed coding this, I hope it helps others :) Good luck on your project! – Omar Nov 20 '13 at 16:51
0

I think that you can use the same approach that I suggested to Ranjan.

Using a textfield like a buffer. First you need to detect when the keyboard appears and check if the first responder is the webview. Then you become a textview as the first responder.

When you are setting the text inside the input of the webview, you can add some logic to validate the number.

Here is a link of my example project with the solution, in your case you don't need change the inputView. But the approach is the same, use a Man in the middle.

Community
  • 1
  • 1
dcorbatta
  • 1,893
  • 19
  • 15
0

Cant comment on https://stackoverflow.com/a/19998430/6437391 so posting as a separate answer...

This is the same idea as https://stackoverflow.com/a/19998430/6437391 but instead of switching the type, its the pattern that's switched.

This has the effect of not clearing the value on the textfield on focus when value does not match numeric format, for example, if the value has separators( 1,234.56 ).

$('input[type="text"]').on('touchstart', function() {
  $(this).attr('pattern', '[0-9]*');
});

$('input[type="text"]').on('focus', function() {
  $(this).attr('pattern', actualpattern);
});