How to detect up and down clicks on html input[number]? - html

I have an html <input type="number"> box that has some custom validation logic. A valid value is any integer x where x < -100 OR x >= 100.
My goal is to implement this behavior:
when the user clicks on the native down arrow or presses the down arrow key and the current value is 100, the value changes to -101.
similarly when the user clicks on the native up arrow or presses the up arrow key and the current value is -101, the value changes to 100.
A few caveats:
Users must still be able to type numbers that fall within the invalid range since they may need to type 10 in order to type 109. And validation logic already occurs for this.
I am using angularjs, but I suspect that the solution is not going to be angular specific.
This is an internal application, meant for Chrome only, so browser specific answers are fine.

I think I have what you need, or at least I'm getting close:
window.onload = function() {
function changeNum(input, typing) {
var lower=-101, upper=100, x=parseInt(input.value), active=(input==document.activeElement);
if ((typing && String(Math.abs(x)).length>2 && lower<x&&x<upper) || (!typing && lower<x&&x<upper)) {
if (Math.abs(x-upper) < Math.abs(x-lower)) {input.value = (!active||typing?upper:lower);}
else {input.value = (!active||typing?lower:upper);}
}
}
document.getElementById("num").addEventListener("keyup",function(){changeNum(this,true);},false);
document.getElementById("num").addEventListener("change",function(){changeNum(this,false);},false);
};
<input type="number" id="num" value="100" />
jsfiddle: https://jsfiddle.net/9zz0ra35/4/
codepen: http://codepen.io/anon/pen/Ndqbog
When the user clicks on the input's up&down-buttons, the value flips over on the lower and upper threshold (-100 -> 100, 99 -> -101).
When the user types a value and then clicks outside the input, invalid values are changed to the closest threshold (-100 -> -101, 99 -> 100).
While typing, invalid values are also changed to the closest threshold, but only if the value.length is more than 2 chars (-100 -> -101).
This last one isn't as clean as the others, because it only works if both the lower and upper threshold have the same length (in this case 3 chars).
But if you need thresholds with different lengths, you can always change the String(Math.abs(x)).length>2 to an extra if-clause and first check whether the value is positive or negative, and then check for separate lengths.

I'm not sure if I'm getting what you want. Is it something like this?
var number = document.getElementById('number-input');
number.onchange = function(event) {
if(number.value > 100) {
number.value = -101;
} else if(number.value < -100) {
number.value = 101;
}
};
<input type="number" id="number-input">

Related

Is there a easy way to handle input type="number" as a default negative value?

I've tried filling the value on init with a "-" sign but only got the Error-Message:
The specified value "-" cannot be parsed, or is out of range.
Another attempt was to just accept every value as negative if it doesn't start with a "+" sign but when reading the value property the sign wasn't included.
Does anyone know an easy way to handle an input type="number" as a negative and only make it positive when explicitly stated?
Preferably in a user-friendly way. I don't want a check-box to handle that.
Specifics:
i have an input Field in html
<input type="number" #testAmount>
I want to handle the value as negative when not explicitly stated otherwise.
so my first attempt was this in TS:
#ViewChild('testAmount') testAmount: ElementRef<HTMLInputElement> | undefined = undefined;
ngOnInit() {
if(!!this.testAmount){
console.log('set amount value');
console.log(this.testAmount.nativeElement.value);
this.testAmount.nativeElement.value = '-'
}
}
that's when i got the error message above:
The specified value "-" cannot be parsed, or is out of range.
Attempt 2:
In my second attempt figured to just accept any value and treat it as negative and only once the user puts a "+" before the value it would be a positive.
but that didn't work out, because when i read the value like this:
console.log(this.testAmount.nativeElement.value)
i was given the value without the + sign, presumably because it was interpreted as a number and thus the + sign was automatically removed.
To Be clear
All i want is that the user doesn't have to add the minus sign every time he adds a value, because negative values will be the norm.
But a positive value shall still be possible it is just rather rare.
Solution?
Best solution i've found so far is to give my input a KeyDown event and handle the very first key-input, it's not perfect but i think it'll get the job done most of the time:
inputHasBeenMade = false
onKeyDown(event: KeyboardEvent) {
if(!this.inputHasBeenMade && !!this.amount){
if(event.key !== "+"){
event.preventDefault()
this.amount.nativeElement.value = '-' + event.key
}
this.inputHasBeenMade = true
}
}
i don't think it's a good solution so i won't write it down as an answer (for now) in the hopes that someone will come up with a better solution.
type number can't have a "-" string.
you can specify -78 or some other number without the ""
Change
let myValue = '-';
this.testAmount.nativeElement.value = myValue
To
let myValue = -5;
this.testAmount.nativeElement.value = myValue;
You are creating a minus symbol when you wrap it with a single ' or a " double quote, and this makes it a string. Remove the quotes and it will be an integer.
You can also look at casting a string to an int if that's required, but not good practice.

Input for currency not treating 0 like other numbers after decimal

I'm make a react application that takes an input that should be shown to two decimal places. When the default input has a one number after the decimal, it should add a second number with a 0 after it. It also lets me add infinite amounts of "0"s, but caps any other number at 2 decimal places.
Two different problems pictured:
Case 1.
This is how the input looks when first loaded. The preferred display would be 1.60 (two decimal places)
Case 2.
Current behavior allows the user to add infinite 0s (any other number it caps at 2 decimal places). Expected behavior should cap all numbers including 0s at 2 decimal places.
function ProductMaterial() {
const [name, setName] = useState("");
function handleChange(e) {
let val = e.target.value;
if (val.includes(".") && val.split(".")[1].length > 2) {
}
else {
setName(parseFloat(val));
setMaterialState(parseFloat(val));
}
}
return (
<div className="input-group-sm col-xs-2 material input-group">
<div className="input-group-prepend">
<span className="input-group-text">$</span>
</div>
<input
className="form-control"
type="number"
min="0.00"
onChange={handleChange}
value={product.material}
/>
</div>
);
}
Here is the code for setMaterialState. It changes the product.material value, and then calls setMaterial() in a useEffect() function. The setMaterial() takes the id of the product, and the new material value and saves it to state.
function setMaterialState(newMaterial) {
product.material = newMaterial;
}
useEffect(() => {
setMaterial(product.id, product.material);
}, [product.material]);
I know that the issue here is that on first load nothing is triggering the onChange() function. I've tried setting value={product.material} to value={product.material.toFixed(2)} but it makes it difficult to fix the input. Is there a good way to initialize it before, maybe using a UseEffect() statement? And on top of this I'm not sure why the 0s can be added indefinitely.
Update:
The first problem with the leading 0s was solved by using the onKeyPress= answer suggested by Photonic.
However, I'm still struggling on the forcing it to be two decimal places when there is a 0 at the end problem. I'm realizing that the issue with not starting doing 1.60 is due to it being converted to a float value and not being a string. I tried doing a UseEffect() [] and force it to go to 2 decimal places with product.material.toFixed(); as well as modify the data to start with being 1.60, but it seems like the only way to force the two decimal places is keeping it as a string or converting it to a string by using product.material.toFixed(2). The value in the input value={product.material} need to be a number to correctly execute calculations and collect user input. I'm not sure what the best solution for this is.
I dont know how you are initializing the first load but you can use UseEffect() to fix the decimal place issue like you mentioned.
For the infinite decimal places...
onChange is an event that is already happen, you might want to try changing from onChange to onKeyDown or onKeyPress and in your code you can add e.preventDefault() to stop number from being entered
if (val.includes(".") && val.split(".")[1].length > 2) {
e.preventDefault()
}
If you want to call a function when the 'component did mount' you can use
useEffect(yourFunction(){}, [])

Chrome clearing input type=number

In the latest release "47.0.2526.73" all my input type="number" are clearing every time that we try to type a float point number, example : 1.1
These inputs have a keyup event handler in jQuery to remove the leading zeros.
This code was working before the latest update.
Is there a bug?
-- UPDATE --
//Fix to leading zero decimals
$('input[type=number]').keyup(function (e) {
if (!this.value && (e.keyCode == 190 || e.keyCode == 110)) {
this.value = '0.';
}
});
This is the code that is not longer working
Change the step so it don't use the default '1' and uses a float. It will allow you to use float numbers and not only integers.
Ex: '0.1'
Looks like chrome is no longer allowing you to read/set the input value for number types using the keyup event when it is in the middle of the decimal point typing.
This is when the user type just '.', you cannot get the value '1.' or set it the same way in the event.
What I did was change the logic to:
$('input[type=number]').keyup(function (e) {
if (this.value) {
if (this.value.charAt(0) == '.')
{
this.value = '0' + this.value;
}
}
});
This is the only way that I have found to fix typing a number without the leading zero in the input box

How to create an input field (HTML) that spans two lines

I want to be able to use an <input> field type of control but allow only two lines.
At the moment I am using two fields but was wondering if anyone can come up with a solution to allow input (similar to a textarea) but no more than two lines. I control the width etc of the field.
For reference, Jquery and Bootstrap 3 are loaded.
Any help much appreciated.
try this
var element = document.getElementById('tworows');
make2Lines(element);
function make2Lines(el){
el.setAttribute('rows', 2); // limit height to 2 rows
// el.setAttribute('wrap', 'off'); // ensure no softwrap is not required anymore if we limit the length
el.addEventListener('keydown', limit); // add listener everytime a key is pressed
function limit(e){
if(e.keyCode == 13 && this.value.indexOf('\n')>-1){
// 13 is the ENTER key and \n is the value it make in the textarea
// so if we already have a line break and it's the ENTER key, we prevent it
e.preventDefault();
}
// async to let the dom update before changin the value
setTimeout(limitRow.bind(this), 0);
}
function limitRow(){
var maxLength = 10;
var rows = this.value.split('\n');
rows.forEach(cutOverflow)
this.value = rows.join('\n');
function cutOverflow(row, index, rows) {
rows[index] = row.substring(0, maxLength);
// this if is only if you want to automatically jump to the next line
if (index === 0 && row.length > maxLength)
rows[1] = row.substring(maxLength) + (rows[1] || '');
}
}
}
<textarea id="tworows"></textarea>
short version : function make2Lines(a){function b(a){13==a.keyCode&&this.value.indexOf("\n")>-1&&a.preventDefault(),setTimeout(c.bind(this),0)}function c(){function c(b,c,d){d[c]=b.substring(0,a),0===c&&b.length>a&&(d[1]=b.substring(a)+(d[1]||""))}var a=10,b=this.value.split("\n");b.forEach(c),this.value=b.join("\n")}a.setAttribute("rows",2),a.addEventListener("keydown",b)}
Two ways come to mind:
You could use a <textarea> instead, and augment it with some script that only allows two lines.
You could continue to use two <input> fields, but style them so they stack on top of each other to create the illusion of one field. You might still need a bit of script to take care of some usability annoyances, such as pressing ENTER to go from line one to line two.
If you are talking about wrapping lines if the text is too long, according to documentation <input type="text"> cannot wrap text.
However, if you are talking about limiting the character length, you could use the maxlength attribute like- <input type="text" maxlength="10">
An input field can only display one line http://www.w3.org/TR/html-markup/input.text.html#input.text. For multiline you need to use textarea and set the rows attribute. If you need two separate values you can do it after in PHP, Javascript or other means.
<textarea class="form-control" rows="2">The default text or empty for nothing this is passed as value for this field</textarea>

How can I make the HTML5 number field display trailing zeroes?

I have a field:
<input type='number' />
I'd like to punch in 0.50 without it “correcting it” to 0.5, so it would display 0.50.
I attached an on('change') event to the input you want to have trailing 0's
$('.number-input').on('change', function(){
$(this).val(parseFloat($(this).val()).toFixed(2));
});
It just takes the value, casts it to a float, renders it to a string to the number of decimal places, and puts it back in as the value.
I've had a little play around with this and looked at the spec. It says that it must be a valid floating point number. There's one sentence in the definition of a valid floating point number it gives which caught my attention:
The best representation of the number n as a floating point number is
the string obtained from applying the JavaScript operator ToString to
n.
This means that the format will always be consistent with assessing what the number is, then using JavaScript's toString on that number. So no trailing 0s then.
So, you're going to have to resort to JavaScript. This isn't straightforward because document.getElementById('numInput').value = '0.50'; still gets corrected to 0.5, so the validation isn't triggered at onchange where the default action can be prevented, it's triggered internally.
This is the best solution I could come up with... it's a bit of a hack, and will need a bit of tweaking for robustness, but hopefully it'll do what you want:
var numInput = document.getElementById('numInput');
numInput.addEventListener('keypress', function () {
this.setAttribute('type', 'text');
});
numInput.addEventListener('click', function () {
this.setAttribute('type', 'number');
});
So if the user wants to enter the number by typing, it switches the input type to text, but when they click it, it converts it back to a number.
If you always want the trailing 0s no matter what the user types, then you could do it something like this:
var numInput = document.getElementById('numInput');
numInput.addEventListener('blur', function () {
if (this.value === '') {
return;
}
this.setAttribute('type', 'text');
if (this.value.indexOf('.') === -1) {
this.value = this.value + '.00';
}
while (this.value.indexOf('.') > this.value.length - 3) {
this.value = this.value + '0';
}
});
numInput.addEventListener('focus', function () {
this.setAttribute('type', 'number');
});
Edit: I think the second solution is more inline with what the user might expect, but it means that if the user types 0.5 it will be coerced to 0.50, so it depends if that's what you want.