vuejs-vmodel-binding-datos

Binding de datos con v-model en Vue.js

  • 5 min

En Vue.js, la directiva v-model permite crear un binding bidireccional entre un elemento de formulario HTML y una variable de JavaScript en la instancia de Vue.

El binding bidireccional funciona en ambos sentidos, desde los datos en el JavaScript al HTML y viceversa.

Es decir,

  • Cualquier cambio en el elemento de formulario ➡️ se reflejará en los datos
  • Cualquier cambio en los datos ➡️ se reflejará en el elemento de formulario.

Directiva v-model

Como decíamos la directiva v-model permite hacer un binding bidireccional que funciona entre los datos del JavaScript y al HTML.

El enlace ocurre entre un elemento de formulario (como <input>, <textarea>, o <select>), que son los elementos que pueden recibir una entrada de datos por el usuario.

El binding con v-model permite que los cambios en el elemento de formulario se reflejen automáticamente en los datos, y viceversa.

<template>
  <input v-model="message" placeholder="Escribe algo" />
  <p>Mensaje: {{ message }}</p>
</template>

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

const message = ref('');
</script>

En este ejemplo:

  • El valor del campo de texto está enlazado a la variable message.
  • Si el usuario escribe en el campo, message se actualiza automáticamente.
  • Si message cambia en el script, el campo de texto se actualiza automáticamente.

Bajo el capó v-model

<input v-model="message">

Básicamente es lo mismo que un binding de value y un handler para input

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

Uso de v-model con diferentes elementos de formulario

El v-model se comporta de manera (ligeramente) diferente según el tipo de elemento de formulario al que lo apliquemos.

En función del elemento en el que lo usemos, será,

ElementoAtributo vinculadoTipo de datoComportamiento
<input> (texto)valueStringEl valor del input se vincula a la propiedad. Actualiza bidireccionalmente.
<textarea>valueStringEl contenido del textarea se vincula a la propiedad. Actualiza bidireccionalmente.
<select>value de la opción seleccionadaString (o array)El valor seleccionado se vincula a la propiedad. En multiple, es un array.
<input> (checkbox)checkedBoolean (o array si es multiple)El estado de marcado se vincula a la propiedad. En multiple, es un array.
<input> (radio)checkedStringEl valor de la opción seleccionada se vincula a la propiedad. Solo una opción puede estar seleccionada.

Vue maneja el vínculo de manera adecuada para asegurar que los datos se actualicen correctamente en ambas direcciones.

<template>
  <input v-model="text" type="text" placeholder="Escribe algo" />
  <p>Texto ingresado: {{ text }}</p>
</template>

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

const text = ref('');
</script>
<template>
  <textarea v-model="description" placeholder="Escribe una descripción"></textarea>
  <p>Descripción: {{ description }}</p>
</template>

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

const description = ref('');
</script>
<template>
  <select v-model="selectedOption">
    <option value="opcion1">Opción 1</option>
    <option value="opcion2">Opción 2</option>
    <option value="opcion3">Opción 3</option>
  </select>
  <p>Opción seleccionada: {{ selectedOption }}</p>
</template>

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

const selectedOption = ref('opcion1');
</script>
<template>
  <label>
    <input type="checkbox" v-model="isChecked" />
    ¿Estás de acuerdo?
  </label>
  <p>Estado del checkbox: {{ isChecked ? 'Sí' : 'No' }}</p>
</template>

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

const isChecked = ref(false);
</script>

Modificadores de v-model

Los modificadores de v-model permiten ajustar el comportamiento de la sincronización de datos entre el estado y el DOM en Vue.js.

ModificadorDescripción
.lazyActualiza el valor solo después de que ocurra el evento change
.numberConvierte automáticamente el valor de la entrada en un número
.trimElimina los espacios en blanco al principio y al final del valor.

El modificador .lazy hace que v-model actualice el valor solo después del evento change (en lugar de input).

<template>
  <input v-model.lazy="message" placeholder="Escribe algo" />
  <p>Mensaje: {{ message }}</p>
</template>

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

const message = ref('');
</script>

En este ejemplo:

  • El valor de message se actualiza solo cuando el campo de texto pierde el foco.

El modificador .number convierte automáticamente la entrada a un número.

<template>
  <input v-model.number="age" type="number" placeholder="Edad" />
  <p>Edad: {{ age }} ({{ typeof age }})</p>
</template>

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

const age = ref(0);
</script>

En este ejemplo:

  • La entrada se convierte automáticamente a un número.

El modificador .trim elimina espacios en blanco al principio y al final de la entrada.

<template>
  <input v-model.trim="username" placeholder="Nombre de usuario" />
  <p>Nombre de usuario: "{{ username }}"</p>
</template>

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

const username = ref('');
</script>

En este ejemplo:

  • Los espacios en blanco al principio y al final se eliminan automáticamente.

Es posible combinar varios modificadores para lograr un comportamiento más preciso.

<input v-model.lazy.trim.number="amount" />

Uso de v-bind en nuestros componentes Avanzado

v-model también se puede usar en nuestros propios componentes para crear un enlace bidireccional entre el componente padre y el componente hijo.

CustomInput.vue

<template>
  <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />
</template>

<script setup>
defineProps({
  modelValue: String,
});

defineEmits(['update:modelValue']);
</script>

ParentComponent.vue

<template>
  <CustomInput v-model="message" />
  <p>Mensaje: {{ message }}</p>
</template>

<script setup>
import { ref } from 'vue';
import CustomInput from './CustomInput.vue';

const message = ref('');
</script>

En este ejemplo:

  • El componente hijo (CustomInput) recibe la prop modelValue y emite un evento update:modelValue cuando el valor cambia.
  • El componente padre usa v-model para enlazar message con el componente hijo.