Home > Enterprise >  Creating a Search Input Filter with Computed in Vue 3
Creating a Search Input Filter with Computed in Vue 3

Time:03-14

I've worked through this guide to create a search filter input field but can't figure out how to correctly implement computed in the v-model.

I've transformed the code from the guide into:

<template>
  <div id="table-cms" >
    <input  type="search" placeholder="Search" v-model="filter">
    <p>{{ filter }}</p>
    <p>{{ state.array }}</p>
  </div>
</template>


<script setup>
import {computed, reactive} from "vue";

const state = reactive({
    search: null,
    array: [
        {id: 1, title: 'Thanos', content: '123'},
        {id: 2, title: 'Deadpool', content: '456'},
        {id: 3, title: 'Batman', content: '789'}
    ]
})

const filter = computed({
    get() {
        console.log('check1')
        return state.search
    },
    set() {
        if (state.search) {
            console.log('check2a')
            return state.array.filter(item => {
                return state.search
                    .toLowerCase()
                    .split(" ")
                    .every(v => item.title.toLowerCase().includes(v))
            });
        } else {
            console.log('check2b')
            return state.array;
        }
    }
})
</script>

But the console shows:

check1
check2b
check2b
check2b
...

This means that computed gets executed but it doesn't enter if (state.search) {} (the actual filter). Displaying state.array does render the initial array but does not get updated by typing different titles in the input field:

<p>{{ state.array }}</p>

rendering:

[
  {
    "id": 1,
    "title": "Thanos",
    "content": "123"
  },
  {
    "id": 2,
    "title": "Deadpool",
    "content": "456"
  },
  {
    "id": 3,
    "title": "Batman",
    "content": "789"
  }
]

What am I doing wrong?

CodePudding user response:

You have to use state.search as the v-model on your input:

<input  type="search" placeholder="Search" v-model="state.search">

Otherwise it stays null forever because it is not changing which causes the code to skip the if statement.

Also you don't need a setter in your computed filter.

<template>
    <div id="table-cms" >
        <input
            
            type="search"
            placeholder="Search"
            v-model="state.search"
        />
        <p>{{ state.array }}</p>
    </div>
</template>

<script setup>
import { computed, reactive } from "vue";

const state = reactive({
    search: null,
    array: [
        { id: 1, title: "Thanos", content: "123" },
        { id: 2, title: "Deadpool", content: "456" },
        { id: 3, title: "Batman", content: "789" },
    ],
});

const filter = computed(() => {
    if (state.search) {
        //console.log('check2a')
        return state.array.filter((item) => {
            return state.search
                .toLowerCase()
                .split(" ")
                .every((v) => item.title.toLowerCase().includes(v));
        });
    } else {
        console.log("check2b");
        return state.array;
    }
});
</script>
  • Related