Hamburger Icon
Cómo usar la directiva v-model con componentes personalizados en Vue.js

Cómo usar la directiva v-model con componentes personalizados en Vue.js

En este post vamos a ver cómo podemos hacer un bind bidireccional entre elementos que están en componentes diferentes aprovechándonos de la reactividad, las propiedades y los eventos.

Cuando trabajamos con Vue.js es común que extraigamos muchas pequeñas partes de la web en pequeños componentes reutilizables. Un caso habitual son los inputs de los formularios. Tenemos un componente que es un input. Ahora bien, cuando hacemos eso, ¿cómo hacemos el bind entre el componente del input y los datos del componente superior? Vamos a verlo.

Qué hace la directiva v-model

En Vue.js usamos esta directiva cuando queremos que dos elementos estén enlazados, lo que comúnmente se llama bind bidireccional.

En otras palabras, cuando el valor de uno de los elementos cambia, también se ve reflejado ese cambio en el otro elemento.

Se suele usar en los formularios para vincular la información que introduce el usuario con los datos del componente. Puedes ver un ejemplo en este sandbox.

Cómo funciona v-model

Antes de empezar es muy importante entender cómo funciona la directiva v-model, ya que necesitaremos crear el mismo comportamiento.

Cuando usamos la directiva v-model Vue.js enlazará el valor del campo con el elemento que hayamos indicado, gestionando automáticamente los eventos input o change dependiendo del tipo de input.

Es decir, el input está enlazado con un elemento y se actualiza a través de eventos. Cuando escribimos en la caja de texto se ejecuta el evento input, lo que provoca que se actualice nuestro elemento con el valor del input.

Visto en forma de código:

<input v-bind:value="nombre" v-on:input="nombre = $event.target.value" />

Es equivalente a:

<input v-model="nombre" />

Enlazando datos con un componente input hijo

Vamos a crear primero el componente input. Puntos a tener en cuenta:

  • El valor del input tiene que estar enlazado con v-bind con una propiedad que le pasaremos al componente

  • Cuando ocurra el evento input en la caja de texto, hay que emitir otro evento input hacia el componente padre con el valor que tenga la caja de texto en ese momento

Veamos el código:

// CustomTextInput.vue
<template>
  <label :for="inputName">
    <!-- recuerda que ':' es lo mismo que 'v-bind:' en Vue.js -->
    <input
      :name="inputName"
      type="text"
      :value="inputValue"
      v-on:input="handleInput"
    />
  </label>
</template>

<script>
export default {
  name: "CustomTextInput",
  props: {
    inputName: String, // hacemos dinamico el nombre del input
    inputValue: String, // enlace con el valor que haya en el input
  },
  methods: {
    handleInput(event) {
      // emitimos evento input hacia el componente de arriba, con el valor que haya introducido el usuario
      this.$emit("input", event.target.value);
    },
  },
};
</script>

Cuando queramos llamar a este componente tendremos que:

  • Pasarle el nombre del componente con la propiedad inputName, para crear la estructura necesaria con el label y el input

  • Enlazar con v-model el componente personalizado con los datos del componente padre que nos interese, en este ejemplo nombreUsuario

// App.vue
<CustomTextInput inputName="nombre" v-model="nombreUsuario" />

Puedes ver el ejemplo en acción en este otro sandbox.

También puedes consultar la documentación oficial para ver ejemplos con otros tipos de input, como seleccionables, checkboxes, textareas, etc.