3 minutos de lectura

Crea un buscador en tiempo real con Vue

Muchos proyectos hacen uso de un buscador de contenido, y si estás aquí es que seguro quieres aprender cómo hacerlo. Te voy a mostrar cómo trabajarlo con Vue y para esto vas a hacer uso de los métodos de javascript filter(), find() e includes().

(Voy asumir que ya tienes un proyecto iniciado con vue-cli)

Para este ejemplo voy a trabajar con los personajes de la serie Breaking Bad, haciendo uso de la API https://www.breakingbadapi.com

Bien, ya tienes lo básico para iniciar.
Lo voy a trabajar directamente del archivo App.vue (si prefieres puedes crear un componente).

Lo primero por hacer en el markup es un campo de búsqueda, haciendo uso de la directiva v-model con el valor de query para crear un enlace bidireccional con la instancia de Vue.

<label>
  Buscador:
  <input type="search" v-model="query">
</label>

Lo siguiente será utilizar la directiva v-for para hacer un recorrido por todos los elementos del array de personajes.

Para que se muestren mejor organizados los pondré dentro de una tabla.

<table style="width: 100%">
  <thead>
    <tr>
      <th>Nombre</th>
      <th>Apodo</th>
      <th>Estado</th>
      <th>Foto</th>
    </tr>
  </thead>
  <tbody>
    <tr v-for="character in filteredCharacters">
      <td>{{ character.name }}</td>
      <td>{{ character.nickname }}</td>
      <td>{{ character.status }}</td>
      <td>
        <img :src="character.img" style="max-width: 75px">
      </td>
    </tr>
  </tbody>
</table>

Ve hasta el tag <script></script> y hay que empezar declarando las variables que se van a necesitar dentro de data, query el campo que servirá para hacer la consulta será de tipo String y characters será un Array que anidara los datos de la API.

<script>
export default {
  name: 'App',
  data () {
    return {
      query: '',
      characters: []
    }
  }
}
</script>

Ahora hay que empezar con la lógica. En created() se va ejecutar la función fetchAllCharacters() la cual hace la petición a la API https://www.breakingbadapi.com/api/characters y carga los datos al array characters.

// data () {...},
created () {
  this.fetchAllCharacters()
},
methods: {
  fetchAllCharacters () {
    fetch('https://www.breakingbadapi.com/api/characters')
      .then(res => res.json())
      .then(res => this.characters = res)
      .catch(err => console.log(err))
  }
}

Lo primero que hará Vue será revisar la consulta de la variable query, si viene vacía, retorna todos los registros, de lo contrario pasa a la lógica de filtrado, está recorre cada elemento creando un nuevo array de cada uno.

Para hacer más fácil la consulta, haré uso de un array con los campos que deseo filtrar.

Para evitar conflictos en la consulta es recomendable cambiar el texto a minúsculas con toLowerCase() y eliminar los espacios vacíos con trim().

filteredCharacters () {
  if (!this.query) return this.characters

  return this.characters.filter(character => {
    return [
      character.name,
      character.nickname,
      character.status
    ].find(field => {
      return field.toLowerCase().includes(this.query.toLowerCase().trim())
    })

  })
  
}

Momento de ver como funciona.

Al escribir en el campo de búsqueda Vue actualiza el modelo por medio de la directiva v-model y reacciona para computar la información en filteredCharacters() actualizando de nuevo los datos de salida que se representarán en la directiva v-for.

Aquí está el código final:

<template>
  <div>
    <label>
      Buscador:
      <input type="search" v-model="query">
    </label>

    <table style="width: 100%">
      <thead>
        <tr>
          <th>Nombre</th>
          <th>Apodo</th>
          <th>Estado</th>
          <th>Foto</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="character in filteredCharacters">
          <td>{{ character.name }}</td>
          <td>{{ character.nickname }}</td>
          <td>{{ character.status }}</td>
          <td>
            <img :src="character.img" style="max-width: 75px">
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>
export default {
  name: 'App',
  data () {
    return {
      query: '',
      characters: []
    }
  },
  computed: {
    filteredCharacters () {
      if (!this.query) return this.characters

      return this.characters.filter(character => {
        return [
          character.name,
          character.nickname,
          character.status
        ].find(field => {
          return field.toLowerCase().includes(this.query.toLowerCase().trim())
        })

      })
      
    }
  },
  created () {
    this.fetchAllCharacters()
  },
  methods: {
    fetchAllCharacters () {
      fetch('https://www.breakingbadapi.com/api/characters')
        .then(res => res.json())
        .then(res => this.characters = res)
        .catch(err => console.log(err))
    },
  }
}
</script>

Y esto es todo el código necesario. Sencillo ¿verdad?

Ahora te toca a ti, anímate a agregar nuevas funcionalidades como sortear los resultados, filtrar por otros campos, limitar los resultados, etc.