Home > Back-end >  Checkbox Filter for Search Result in Vue
Checkbox Filter for Search Result in Vue

Time:08-21

I am trying to create a query table with checkbox filter functionality. You can simply run the following code snippet to understand more easily.

When user ticks the checkboxes, the following table should be filtered accordingly.

Now, I have following questions:

  1. How can I make all checkboxes are checked in default? (When user click "Search fruit", they can originally see all checkboxes are checked and all fruits are shown.) I tried to input checked attributed in the HTML, but it doesn't work.

  2. How to bind selected checkboxes with the following table to have a filter functionality? I tried to use v-on:click on each checkbox, but it seems not working...

The following is the simple code snippet:

new Vue({
    el: '#app',
    data: {
        isSearched: false,
        searchList: [],
        data: [ 
            { "name": "apple", "color": "red" },
            { "name": "banana", "color": "yellow" },
            { "name": "strawberry", "color": "red" },
            { "name": "avocado", "color": "green" },
            { "name": "kiwi", "color": "green" },
        ],
        selected: []
    },
    computed: {
        colors() {
           let colors = [];
           this.searchList?.forEach(fruit => {
              if(colors.indexOf(fruit.color) === -1){
                  colors.push(fruit.color);
              }    
           });
         return colors;
           
        },
        selectAll: {
            get(){
                return this.colors.length == this.selected.length;
            },
            set(value){
                let selected = [];

                if (value) {
                    this.colors.forEach(color => {
                        selected.push(color);
                    });
                }

                this.selected = selected;
            }
        }
    },
    methods: {
      search() {
        this.searchList = this.data;
        this.isSearched = true;
      }
    }
});
table, td, th{
  border: 1px solid black;
  border-collapse: collapse;
}
<script src="https://cdn.jsdelivr.net/vue/latest/vue.js"></script>

<div id="app">
<button @click="search">Search Fruit</button>
<br/><br/>
<div v-if="isSearched">
    <table>
        <tr>
            <th colspan="2">Filter</th>
        </tr>
        <tr>
            <th>
                <input type="checkbox" 
                       v-model="selectAll"
                       />
            </th>
            <th align="left">All Color</th>
        </tr>
        <tr v-for="color in colors">
            <td>
                <input type="checkbox" 
                        v-model="selected" 
                        :value="color" 
                        checked/>
            </td>
            <td>{{ color }}</td>
        </tr>
    </table>
    <br/>
    <table>
        <tr>
            <th>Name</th>
            <th>Color</th>
        </tr>
        <tr v-for="fruit in searchList">
            <td>{{ fruit.name }}</td>
            <td>{{ fruit.color }}</td>
        </tr>
    </table>
</div>
</div>

CodePudding user response:

The reason why checked attribute does not work initially is here:

v-model will ignore the initial value, checked, or selected attributes found on any form elements. It will always treat the Vue instance data as the source of truth. You should declare the initial value on the JavaScript side, inside the data option of your component.

Therefore this.selected = [...this.colors]; is in search method in the following code snippet. Also, searchList is a computed property and colors computed property has been changed for filter.

new Vue({
  el: '#app',
  data: {
    isSearched: false,
    data: [{
        "name": "apple",
        "color": "red"
      },
      {
        "name": "banana",
        "color": "yellow"
      },
      {
        "name": "strawberry",
        "color": "red"
      },
      {
        "name": "avocado",
        "color": "green"
      },
      {
        "name": "kiwi",
        "color": "green"
      },
    ],
    selected: []
  },
  computed: {
    colors() {
      let colors = [];
      this.data.forEach(fruit => {
        if (colors.indexOf(fruit.color) === -1) {
          colors.push(fruit.color);
        }
      });
      return colors;

    },
    selectAll: {
      get() {
        return this.colors.length == this.selected.length;
      },
      set(value) {
        let selected = [];

        if (value) {
          this.colors.forEach(color => {
            selected.push(color);
          });
        }

        this.selected = selected;
      }
    },
    searchList() {
      const filteredList = [];
      this.selected.forEach(color => {
        this.data.forEach(x => {
          if (x.color === color) {
            filteredList.push(x);
          }
        });
      });
      return filteredList;
    }
  },
  methods: {
    search() {
      this.isSearched = true;
      
      this.selected = [...this.colors];
    }
  }
});
table,
td,
th {
  border: 1px solid black;
  border-collapse: collapse;
}
<script src="https://cdn.jsdelivr.net/vue/latest/vue.js"></script>

<div id="app">
  <button @click="search">Search Fruit</button>
  <br/><br/>
  <div v-if="isSearched">
    <table>
      <tr>
        <th colspan="2">Filter</th>
      </tr>
      <tr>
        <th>
          <input type="checkbox" v-model="selectAll" />
        </th>
        <th align="left">All Color</th>
      </tr>
      <tr v-for="color in colors">
        <td>
          <input type="checkbox" v-model="selected" :value="color" />
        </td>
        <td>{{ color }}</td>
      </tr>
    </table>
    <br/>
    <table>
      <tr>
        <th>Name</th>
        <th>Color</th>
      </tr>
      <tr v-for="fruit in searchList">
        <td>{{ fruit.name }}</td>
        <td>{{ fruit.color }}</td>
      </tr>
    </table>
    
    <br/>
    <br/>
    <br/>
    <br/>
    <br/>
    <br/>
  </div>
</div>

  • Related