Can I have a number input element where the digits are entered right to left without manual cursor movement in between? The application is for training basic mental arithmetic, where that order is more natural.
I'd like to also have my input element configured as a number. Both the automatic addition of stepper buttons on desktop and the choice of a numeric keyboard on mobile devices are beneficial.
https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange writes:
Note that according to the WHATWG forms spec selectionStart, selectionEnd properties and setSelectionRange method apply only to inputs of types text, search, URL, tel and password. Chrome, starting from version 33, throws an exception while accessing those properties and method on the rest of input types. For example, on input of type number: "Failed to read the 'selectionStart' property from 'HTMLInputElement': The input element's type ('number') does not support selection".
And indeed, while I can get what I want fairly easily for a text input, it fails for me on recent Chrome with a number input element, as my demo below shows. The current selection endpoints are always null for a number input element.
Is there any way to work around the restrictions and manipulate the cursor / caret position of a number element? Or, barring that, any way to make a text element reject non-digit input, show a stepper and use a numeric keyboard, ideally without linking in heavy library dependencies like Angular?
const dbg = document.getElementById("dbg");
["txt", "num"].forEach(id => {
const elt = document.getElementById(id);
elt.addEventListener("input", evnt => {
dbg.innerText = `evnt.inputType = ${evnt.inputType}, elt.selectionStart = ${elt.selectionStart}, elt.selectionEnd = ${elt.selectionEnd}`;
if (evnt.inputType == "insertText" &&
elt.selectionStart === 1 &&
elt.selectionEnd === 1) {
elt.setSelectionRange(0, 0);
}
});
});
<p>Text: <input type="text" id="txt"></p>
<p>Number: <input type="number" id="num"></p>
<p>Debug: <span id="dbg"></span></p>
You can do that using CSS.
<p>Text: <input type="text" id="txt" style="direction: rtl"></p>
<p>Number: <input type="number" id="num" style="direction: rtl"></p>
<p>Debug: <span id="dbg" ></span></p>
Related
I have a form in Vue that has some combined inputs for styling reasons for a phone number input.
My problem is that the user has to hit tab in order to go to the next input field of the phone number.
Is there a way to check for the max length of the current and input and when that is met go to the next input?
<div class="combined-input combined-input--phone" :class="{'error--input': phoneInvalid('patientInformation')}">
<div class="open-parenthesis"></div>
<input type="text" id="phoneArea" maxlength="3" #blur="$v.formData.patientInformation.phone.$touch()" v-model.trim="$v.formData.patientInformation.phone.area.$model">
<div class="close-parenthesis"></div>
<input type="text" id="phoneA" maxlength="3" #blur="$v.formData.patientInformation.phone.$touch()" v-model.trim="$v.formData.patientInformation.phone.a.$model">
<div class="dash"></div>
<input type="text" id="phoneB" maxlength="4" #blur="$v.formData.patientInformation.phone.$touch()" v-model.trim="$v.formData.patientInformation.phone.b.$model">
</div>
Pretty sure this is not recommended UX-wise but here is an example on how you can achieve it: https://codesandbox.io/s/move-to-next-input-on-condition-103b5?file=/src/App.vue
The main part of useful code is
focusNextOncePopulated(event, max) {
if (event.target.value.length === max) {
const nextElement = this.$refs?.[`input-${Number(event.target.dataset.index) +1}`]
if (nextElement) nextElement.focus()
}
},
Explanation: each time you input a char, you check if the length of the field reached the maximum you've set on a particular input. If it is and there is a similar input as a sibling, you focus it.
Adding a debounce of a few milliseconds would be nice too, performance-wise.
EDIT: to prevent any issues of trying to find the correct next input in the DOM, we setup some refs on each of the inputs (recommended way in Vue to select some DOM elements). Then, when we have reached the max, we increment our current's input data-index by one, which enables us to go to the next input.
PS: ?. syntax is optional chaining, it prevents ugly code and allows to avoid an error if there is no next input once max is reached.
PS: Not sure if there is a way to directly get the $refs of an element on it's #input event but if there is, I didn't found out how to do it.
I trying to get cursor position inside input field, which is type number
<input type="number" id="myInput">
And I tried standard selectionStart property, but apparently it does not work for number fields.
var start = document.getElementById("myInput").selectionStart;
Is there any why or workaround to get that information inside keypress event?
My end goal is it prevent leading zeros in such input field, for that I need to know is user input coming to start of existing value.
Currently I stripping those zeros in keyup event:
var inputFieldValue = $(this).val();
$(this).val(removeLeadingZeros(inputFieldValue)); // removeLeadingZeros: inputString.replace(/^0+/, "");
But with that solution those zeros became visible for a second before been removed,
that behavior I want to prevent.
Any ideas? How I can get end result string before it provided to user inside input element? Even as selectionStart value not available for number input, browser somehow know where to put those new characters, so there must be some way to capture that and may be prevent some default behavior or stop bubbling.
You can try RegExp
<input type="number" id="myInput">
$("#myInput").on("input", function() {
if (/^0/.test(this.value)) {
this.value = this.value.replace(/^0/, "")
}
});
I'm having problems with an input type number in HTML5 combining it with an oninput event to have an optional max length qith an optional n max decimals in it. I have the following example code:
<input type="number" name="name" step="any"
oninput=" this.value = (this.value.length > 8) ? this.value.slice(0,8) : this.value; /^[0-9]+(.[0-9]{1,3})?$/.test(this.value) ? this.value : this.value = this.value.slice(0,-1); ">
It works fine except that when a dot is pressed down it removes the entire number without any kind of error. It works with ',' but on mobile I will need the '.' for keyboard purposes. (I need that works too like now with ',')
Your main problem is your text disappearing if you enter a non-numeric character. (Depending on your browsers localization settings, a dot could be considered non-numeric.) The problem is that entering a non-numeric value puts the element into an invalid state, and the element's value cannot be retrieved.
Fortunately, HTML can do this validation by itself, using the step attribute. You don't get the satisfaction of bad characters being immediately erased, but the input will show as invalid once it loses focus. And if needed, you can set custom error messages for the element.
<input
id="identification"
type="number"
name="name"
step="0.001"
min="0"
max="99999999"
/>
Since you only want to control the length of the total number and of its decimal part, I would recommend the keydown event instead of the input event. The following expression
<input type="number" name="name" step="any" onkeydown=
"return event.keyCode<32 || this.value.length<8 && /^\d*([.,]\d{0,2})?$/.test(this.value)"
>
suppresses input if more than 8 characters
suppresses input if more than 3 decimals are entered
allows special keys like backspace
disallows non-numeric input (automatic by type="number")
i have input with type number like this
<input type="number" class="number" min="0" max="999999" value="0" id="id">
when i use this code
$("#id").val();
if it's number like 1 it return the number
but if not a number like 1+1 it return empty string ""
so can i get the actual value with type number or i have to change to text to do so
i test it with chrome and firefox
i know that it will work with type text
but i'm looking to faster solution if there are non then i will change it to text and rewrite the code
here is my question
now when i change the type to text using jquery it remove the value can i change it without remove the value ?
$('#id').attr('type','text')
what i want to do is make the type text get the value and return it back to number
You can not do it with <input type='number'/>,
<input type="number" > will expect you to put a number, so if you put anything like 1+1, it is not considered a number, so returns an empty string "".
you can instead use <input type=text/>
See this fiddle
$('input').on('change', function() {
var strVal = $("#id").val();
var intVal = eval(strVal);
alert(intVal);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" class="number" value="0" id="id">
Edit:
if you cant change whole html, you can change type of the element using jquery,
$('input[type=number]').attr('type','text')
just put this on page load
If someone needs an input type="number" , there is a reason.
Premise: I'm not the same Robert that made the initial question :-)
but ...
I was exactly in the same situation of the Robert who made the initial question ( destiny matter? ), anyway
making a deeper research, I have found this answer
JavaScript get clipboard data on paste event (Cross browser)
I beloved that twice because, nevertheless, it is pure vanilla javascript
I have made this code with input type = "number" and it works like a charm
The main behavior because I want input type = "number" is that this input type, when focused ON MOBILE will open the numbers pad INSTEAD than the letters keyboard. Here the input is driven, you can press only numbers and dashes
But in my app , they can paste the number.. so having a check on the paste event, is a logical consequence
try it
function handlePaste (e) {
var clipboardData, pastedData;
// Stop data actually being pasted into div
e.stopPropagation();
e.preventDefault();
// Get pasted data via clipboard API
clipboardData = e.clipboardData || window.clipboardData;
pastedData = clipboardData.getData('Text');
// Do whatever with pasteddata
alert(pastedData);
}
document.getElementById('myInput').addEventListener('paste', handlePaste);
<p>This example uses the addEventListener() method to attach a "paste" event to an input type="number" element. Paste some text in the input...</p>
<input type="number" id="myInput" value="Try to paste something in here" size="40">
OK Solution to your problem
$('input[type=number]').each(function(){
var val = $(this).val();
$(this).attr('type','text');
$(this).val(val);
});
above code will work on all inputs with type number. If you want to use only one use class or id in first line. If you want to count value from string like 1+1 u can use eval in try catch block. But this is generally a lot more complicated solution.
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
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/
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:
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.
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);
});