Home > Software engineering >  How can I control the content of <input> element with Vue?
How can I control the content of <input> element with Vue?

Time:07-24

I want to have full control over the content of <input> element.

With React, I can do that like:

import { useState } from "react";

function Form() {
  const [value, setValue] = useState("");

  const onSubmit = (event) => {
    event.preventDefault();
    // Do something with `value`
  };

  const onChange = (event) => {
    const { value } = event.target;
    // For example, users can type only uppercase letters
    if (value === value.toUpperCase()) {
      setValue(value);
    }
  };

  return (
    <form onSubmit={onSubmit}>
      <input onChange={onChange} value={value} />
      <button type="submit">Submit</button>
    </form>
  );
}

export default Form;

In Vue, however, I cannot control <input> like:

<script setup>
import { ref } from "vue";

const value = ref("");

const onSubmit = () => {
  // Do something with `value`
};

const onInput = (event) => {
  // For example, users can type only uppercase letters
  if (event.target.value === event.target.value.toUpperCase()) {
    value.value = event.target.value;
  }
};
</script>

<template>
  <form v-on:submit.prevent="onSubmit">
    <input v-on:input="onInput" v-bind:value="value" />
    <button type="submit">Submit</button>
  </form>
</template>

It looks Vue doesn't control the <input> element's value attribute and Vue's value ref differs from value in DOM.

How can I do the same thing as React in Vue? Thank you in advance.

CodePudding user response:

All you need is v-model, v-model can do two-way binding with value property and input event.

So

<input  
  v-model="inputValue"
>

Is equal.

<input  
  :value="inputValue"
  @input="event => inputValue = event.target.value"
>

So in you example you need.

<script setup>
import { ref } from "vue";

const inputValue = ref("");

const onSubmit = () => {
 console.log(inputValue.value)
  // Do something with `value`
};

</script>

<template>
  <form v-on:submit.prevent="onSubmit">
    <input v-model="inputValue" />
    <button type="submit">Submit</button>
  </form>
</template>

This is a live code example of what you are looking for.

https://stackblitz.com/edit/vue3-script-setup-with-vite-ze8fvb?file=src/App.vue

CodePudding user response:

If you bind a function to input or change events, the first parameter of the function is the event. If you want to prevent the event (that is, to prevent the change the user just attempted), all you have to do is call .preventDefault() on the event.

Documentation:

So, in your @change or @input handler, check whatever custom logic you want and, should you decide the change is not allowed, call .preventDefault() on the event.


That being said, keep in mind it is generally a bad idea to call .preventDefault() on user input. It's generally perceived as disrespectful. For example, checkouts using .preventDefault have a lower conversion rate than the ones who tell user what's wrong with the input, without preventing the change. One could say .preventDefault prevents sells on checkout pages.

A better idea is to allow the change and tell the user what's wrong with the current value.

  • Related