Saltar al contenido

Enlaces de Entrada de Formulario

Al trabajar con formularios en el frontend, a menudo necesitamos sincronizar el estado de los elementos de entrada del formulario con el estado correspondiente en JavaScript. Puede ser engorroso configurar manualmente los enlaces de valor y los oyentes de eventos de cambio:

template
<input
  :value="text"
  @input="event => text = event.target.value">

La directiva v-model nos ayuda a simplificar lo anterior a:

template
<input v-model="text">

Además, v-model se puede usar en inputs de diferentes tipos, elementos <textarea> y <select>. Se expande automáticamente a diferentes pares de propiedades DOM y eventos según el elemento en el que se utilice:

  • Los <input> con tipos de texto y los elementos <textarea> usan la propiedad value y el evento input;
  • Los <input type="checkbox"> y los <input type="radio"> usan la propiedad checked y el evento change;
  • Los <select> usan value como una prop y change como un evento.

Nota

v-model ignorará los atributos value, checked o selected iniciales encontrados en cualquier elemento de formulario. Siempre tratará el estado JavaScript enlazado actual como la fuente de verdad. Debes declarar el valor inicial en el lado de JavaScript, usando la opción datalas APIs de reactividad.

Uso Básico

Texto

template
<p>Message is: {{ message }}</p>
<input v-model="message" placeholder="edítame" />

El mensaje es:

Nota

Para lenguajes que requieren un IME (chino, japonés, coreano, etc.), notarás que v-model no se actualiza durante la composición del IME. Si también deseas responder a estas actualizaciones, usa tu propio oyente de eventos input y un enlace value en lugar de usar v-model.

Texto Multilínea

template
<span>Multiline message is:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<textarea v-model="message" placeholder="añade múltiples líneas"></textarea>
El mensaje multilínea es:

Ten en cuenta que la interpolación dentro de <textarea> no funcionará. Usa v-model en su lugar.

template
<!-- mal -->
<textarea>{{ text }}</textarea>

<!-- bien -->
<textarea v-model="text"></textarea>

Casilla de Verificación

Casilla de verificación única, valor booleano:

template
<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>

También podemos enlazar múltiples casillas de verificación al mismo array o valor de Set:

js
const checkedNames = ref([])
js
export default {
  data() {
    return {
      checkedNames: []
    }
  }
}
template
<div>Nombres seleccionados: {{ checkedNames }}</div>

<input type="checkbox" id="jack" value="Jack" v-model="checkedNames" />
<label for="jack">Jack</label>

<input type="checkbox" id="john" value="John" v-model="checkedNames" />
<label for="john">John</label>

<input type="checkbox" id="mike" value="Mike" v-model="checkedNames" />
<label for="mike">Mike</label>
Nombres seleccionados: []

En este caso, el array checkedNames siempre contendrá los valores de las casillas de verificación actualmente marcadas.

Botón de Radio

template
<div>Seleccionado: {{ picked }}</div>

<input type="radio" id="one" value="Uno" v-model="picked" />
<label for="one">Uno</label>

<input type="radio" id="two" value="Dos" v-model="picked" />
<label for="two">Dos</label>
Seleccionado:

Seleccionar

Selección única:

template
<div>Seleccionado: {{ selected }}</div>

<select v-model="selected">
  <option disabled value="">Por favor selecciona uno</option>
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>
Seleccionado:

Nota

Si el valor inicial de tu expresión v-model no coincide con ninguna de las opciones, el elemento <select> se renderizará en un estado "no seleccionado". En iOS, esto provocará que el usuario no pueda seleccionar el primer elemento porque iOS no dispara un evento change en este caso. Por lo tanto, se recomienda proporcionar una opción deshabilitada con un valor vacío, como se demostró en el ejemplo anterior.

Selección múltiple (enlazada a array):

template
<div>Seleccionado: {{ selected }}</div>

<select v-model="selected" multiple>
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>
Seleccionado: []

Las opciones de selección se pueden renderizar dinámicamente con v-for:

js
const selected = ref('A')

const options = ref([
  { text: 'Uno', value: 'A' },
  { text: 'Dos', value: 'B' },
  { text: 'Tres', value: 'C' }
])
js
export default {
  data() {
    return {
      Seleccionado: 'A',
      options: [
        { text: 'Uno', value: 'A' },
        { text: 'Dos', value: 'B' },
        { text: 'Tres', value: 'C' }
      ]
    }
  }
}
template
<div>Seleccionado: {{ selected }}</div>

<select v-model="selected">
  <option v-for="option in options" :value="option.value">
    {{ option.text }}
  </option>
</select>
Seleccionado: A

Enlaces de Valor

Para las opciones de radio, casilla de verificación y selección, los valores de enlace de v-model suelen ser cadenas estáticas (o booleanos para la casilla de verificación):

template
<!-- `picked` es una cadena "a" cuando está marcado -->
<input type="radio" v-model="picked" value="a" />

<!-- `toggle` es `true` o `false` -->
<input type="checkbox" v-model="toggle" />

<!-- `selected` es una cadena "abc" cuando la primera opción está seleccionada -->
<select v-model="selected">
  <option value="abc">ABC</option>
</select>

Pero a veces podemos querer enlazar el valor a una propiedad dinámica en la instancia activa actual. Podemos usar v-bind para lograr eso. Además, usar v-bind nos permite enlazar el valor de input a valores que no son cadenas.

Casilla de Verificación

template
<input
  type="checkbox"
  v-model="toggle"
  true-value="yes"
  false-value="no" />

true-value y false-value son atributos específicos de Vue que solo funcionan con v-model. Aquí, el valor de la propiedad toggle se establecerá en 'yes' cuando la casilla esté marcada, y en 'no' cuando esté desmarcada. También puedes enlazarlos a valores dinámicos usando v-bind:

template
<input
  type="checkbox"
  v-model="toggle"
  :true-value="dynamicTrueValue"
  :false-value="dynamicFalseValue" />

Consejo

Los atributos true-value y false-value no afectan el atributo value del input, porque los navegadores no incluyen las casillas desmarcadas en los envíos de formularios. Para garantizar que uno de dos valores se envíe en un formulario (por ejemplo, "sí" o "no"), usa inputs de radio en su lugar.

Botón de Radio

template
<input type="radio" v-model="pick" :value="first" />
<input type="radio" v-model="pick" :value="second" />

pick se establecerá al valor de first cuando el primer input de radio esté marcado, y se establecerá al valor de second cuando el segundo esté marcado.

Opciones de Selección

template
<select v-model="selected">
  <!-- literal de objeto en línea -->
  <option :value="{ number: 123 }">123</option>
</select>

v-model también admite enlaces de valor de tipos que no son cadenas. En el ejemplo anterior, cuando se selecciona la opción, selected se establecerá al valor literal del objeto { number: 123 }.

Modificadores

.lazy

Por defecto, v-model sincroniza la entrada con los datos después de cada evento input (con la excepción de la composición IME como se mencionó anteriormente). Puedes añadir el modificador lazy para sincronizar después de los eventos change en su lugar:

template
<!-- sincronizado después de "change" en lugar de "input" -->
<input v-model.lazy="msg" />

.number

Si deseas que la entrada del usuario se convierta automáticamente a un número, puedes añadir el modificador number a tus inputs gestionados por v-model:

template
<input v-model.number="age" />

Si el valor no puede ser parseado con parseFloat(), se utiliza el valor original (string) en su lugar. En particular, si el input está vacío (por ejemplo, después de que el usuario borre el campo de input), se devuelve una cadena vacía. Este comportamiento difiere de la propiedad DOM valueAsNumber.

El modificador number se aplica automáticamente si el input tiene type="number".

.trim

Si deseas que los espacios en blanco de la entrada del usuario se recorten automáticamente, puedes añadir el modificador trim a tus inputs gestionados por v-model:

template
<input v-model.trim="msg" />

v-model con Componentes

Si aún no estás familiarizado con los componentes de Vue, puedes omitir esto por ahora.

Los tipos de input integrados de HTML no siempre satisfarán tus necesidades. Afortunadamente, los componentes de Vue te permiten construir inputs reutilizables con un comportamiento completamente personalizado. ¡Estos inputs incluso funcionan con v-model! Para saber más, lee sobre Uso con v-model en la guía de Componentes.

Enlaces de Entrada de Formulario
FREE WEEKEND NOW LIVE!
NOW LIVE! Unlimited access to ALL Vue School courses
Join Now
02
days
:
08
hours
:
07
minutes
: