Is there a way to disable the InputNumber component value from changing when pressing Up Arrow, Down Arrow, Home, End keys?
I tried this but it doesn't help:
const onKeyDown = e => {
if (e.key === 'ArrowUp') {
e.preventDefault();
return false;
}
};
example in sandbox
Is there a way to disable the InputNumber component value from changing when pressing Up Arrow, Down Arrow, Home, End keys?
I tried this but it doesn't help:
const onKeyDown = e => {
if (e.key === 'ArrowUp') {
e.preventDefault();
return false;
}
};
example in sandbox
Share Improve this question edited Mar 12 at 7:59 DarkBee 15.5k8 gold badges72 silver badges118 bronze badges asked Mar 12 at 7:40 DZNDZN 1,5843 gold badges24 silver badges49 bronze badges 3 |5 Answers
Reset to default 1Unfortunately this is not available out of the box, however you can override the event handler on the vm. It's a little complicated because you have to recreate all other button handlers like side arrow keys etc. by calling original event, but it's definitely possible.
<script setup>
import InputNumber from "primevue/inputnumber";
import { ref, onMounted } from "vue";
const myinputRef = ref(null);
onMounted(() => {
if (!myinputRef.value) return;
const originalHandler = myinputRef.value.onInputKeyDown.bind(myinputRef.value);
myinputRef.value.onInputKeyDown = function (event) {
if (event.code === "ArrowUp" || event.code === "ArrowDown") {
event.preventDefault();
return;
}
originalHandler(event);
}})
</script>
<template>
<InputNumber ref="myinputRef" />
</template>
I have been at this for a while now. I created a CellEditor component that would additionally allow up/down navigation in a number/text column in a DataTable.
The issue was (and I didn't notice it a first) was that when I would navigate up/down in a column that was using an InputNumber as an editor control, the value would increment/decrement prior to navigation to the next cell's control.
Solution:
Template
<template>
<div @keydown.capture="handleKeydown">
<!-- <input type="number" /> -->
<InputNumber :show-buttons="true"></InputNumber>
</div>
</template>
Script
function handleKeydown(e: any) {
if (shouldBlockKey(e)) {
e.stopPropagation()
e.preventDefault()
}
}
function shouldBlockKey(e: any) {
return e.key === "ArrowUp" || e.key === "ArrowDown"
}
This works because you intercept the event in the capture phase and completely block it from propagating down to the InputNumber completely.
You can still add custom onKeyDown functionality after canceling the event.
Example:
function handleKeydown(e: any) {
const key = e.key;
if (key === "ArrowDown") {
e.preventDefault();
e.stopPropagation();
goToNextEditableRowSameColumn(e);
} else if (key === "ArrowUp") {
e.preventDefault();
e.stopPropagation();
goToPreviousEditableRowSameColumn(e);
}
}
Although @KrysztofKrzeszewski pointed out the answer, unfortunately, it is not possible to influence the behavior externally, but we have the option to override it. However, this does not mean that we cannot use the original functionality (@KrysztofKrzeszewski created a duplication in the answer, which doesn't follow updates).
Before overriding, create a backup of the original function, then call it after your own logic, like this:
- PrimeVue Playground (stackblitz)
import { ref, onMounted } from 'vue';
const value = ref(50);
const myInputNumber = ref(null);
onMounted(() => {
const originalOnKeyDown = myInputNumber.value.onInputKeyDown;
myInputNumber.value.onInputKeyDown = (e) => {
if (['ArrowUp', 'ArrowDown', 'Home', 'End'].includes(e.key)) {
e.preventDefault();
return;
}
originalOnKeyDown(e);
};
});
<InputNumber
ref="myInputNumber"
inputId="minmax"
v-model="value"
:min="0"
:max="100"
/>
Update
My answer inspired @KrzysztofKrzeszewski, so now their answer is complete: Revision #3
Use the
bind()
function to correctly define thethis
.
My solution was complemented with a very correct this fix by @Krzysztof, which ensures that the original function will always run with its own this
. I will also add the updated answer with some documentation and explanation.
Function.prototype.bind()
- MDN Docs- Why use bind() when I can just copy another method by reference? - StackOverflow
The
bind()
method ofFunction
instances creates a new function that, when called, callsthis
function with its this keyword set to the provided value, and a given sequence of arguments preceding any provided when the new function is called.
So the completed answer:
- PrimeVue Playground (stackblitz)
import { ref, onMounted } from 'vue';
const value = ref(50);
const myInputNumber = ref(null);
onMounted(() => {
const originalOnKeyDown = myInputNumber.value.onInputKeyDown.bind(myInputNumber.value);
myInputNumber.value.onInputKeyDown = (e) => {
if (['ArrowUp', 'ArrowDown', 'Home', 'End'].includes(e.key)) {
e.preventDefault();
return;
}
originalOnKeyDown(e);
};
});
<InputNumber
ref="myInputNumber"
inputId="minmax"
v-model="value"
:min="0"
:max="100"
/>
As i said in my comment, use the disabled api in the documentation by binding the value.
Here is the sample.
<template>
<ThemeSwitcher />
<div class="card flex flex-wrap gap-4">
<InputNumber
inputId="minmax"
v-model="value"
:min="0"
:max="100"
@keyup="onKeyUp"
:disabled="isInvalidKey"
/>
</div>
</template>
<script setup>
import { ref } from 'vue';
const value = ref(50);
const isInvalidKey = ref(false); //declare here.
const onKeyUp = (e) => {
if (['ArrowUp', 'ArrowDown', 'Home', 'End'].includes(e.key)) {
console.log('key =', e.key);
isInvalidKey.value = true; // will disabled the input
} else {
isInvalidKey.value = false; // Retain enable input.
}
};
</script>
Attach an event listener to the input element to prevent default behavior of certain keys in input element.
document.getElementById('input-element-id').addEventListener('keydown', function(e) {
if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
e.preventDefault();
}
});
:disabled="isInvalidKey"
, declare thisisInvalidKey
as boolean and make it work in your function. – Keyboard Corporation Commented Mar 12 at 8:14InputNumber
component internally wraps the input element with a <span>, which is why theonKeyDown
event listener does not trigger. You need to access the internal input element within the component and listen for the keydown event. – yuanyxh Commented Mar 12 at 8:32