最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to disable changing the value of <InputNumber> component using up, down, etc. arrows? - Stack Ove

programmeradmin0浏览0评论

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
  • You can use disabled in input, be sure to make your logic correct so when pressing the triggered key, the input will be disabled. Just bind the disabled in the input like :disabled="isInvalidKey", declare this isInvalidKey as boolean and make it work in your function. – Keyboard Corporation Commented Mar 12 at 8:14
  • @KeyboardCorporation can you please code this in sandbox? – DZN Commented Mar 12 at 8:25
  • The InputNumber component internally wraps the input element with a <span>, which is why the onKeyDown 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
Add a comment  | 

5 Answers 5

Reset to default 1

Unfortunately 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 the this.

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 of Function instances creates a new function that, when called, calls this 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();
   }
});

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论