Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue.js : how to filter a table with a custom filter

Table has two columns Name, Age. Searching works by name. As you type the name of user the table will trim down to the specific user name.

But I want it to be filtered by age using a comparison operator < or >.

Code pen link

Html

<div id="demo" class="container">
  <div class="row">
    <div class="col-md-6">
      <input v-model="search" class="form-control" placeholder="Username to search">
    </div>
    <div class="col-md-1">
      <select class="form-control" v-model="searchOperator">
        <option value=">">></option>
        <option value="<"><</option>
      </select>
    </div>
    <div class="col-md-5">
      <input v-model="searchName" class="form-control" placeholder="Age">
    </div>
  </div>
  <table class="table table-striped">
    <thead>
      <tr>
        <th v-repeat="column: columns">
          <a href="#" v-on="click: sortBy(column)" v-class="active: sortKey == column">
            {{ column | capitalize }}
          </a>
        </th>
      </tr>
    </thead>

    <tbody>
      <tr v-repeat="users | filterBy search | orderBy sortKey reverse">
        <td>{{ name }}</td>
        <td>{{ age }}</td>
      </tr>
    </tbody>
  </table>
</div>

Vue :

new Vue({
  el: '#demo',

  data: {
    sortKey: 'name',

    reverse: false,

    searchName: '',

    searchOperator: '',

    searchAge: '',

    columns: ['name', 'age'],

    newUser: {},

    users: [
      { name: 'John', age: 50 },
      { name: 'Jane', age: 22 },
      { name: 'Paul', age: 34 }
    ]
  },

  methods: {
    sortBy: function(sortKey) {
      this.reverse = (this.sortKey == sortKey) ? ! this.reverse : false;

      this.sortKey = sortKey;
    }
  }
});

What is the best approach to achieve this? I tried but nothing seem to be working.

like image 923
Dip Avatar asked Jan 11 '18 07:01

Dip


People also ask

How do you make a filter for Vue?

So if I want to create a filter that's going to apply to more than one Vue component, or element on the page, I can just type in Vue. filter, or Vue. component, and then type in the name of the filter that I want to use, and then put in my function just like I would for whatever method.

Where can Vue filters be applied?

Vue Filters differ from computed properties in two ways. Going off number 2, because VueJS filters are meant for text transformations, they can only be used in two places: mustache interpolations (the curly braces in your template) and in v-bind expressions.


1 Answers

The first thing is : v-repeat is deprecated. So you should be using v-for instead.

<tr v-for="user in filteredPersons">
  <td>{{ user.name }}</td>
  <td>{{ user.age }}</td>
</tr>

filteredPersons is the name of a computed function that returns an array :

computed: {
    filteredPersons: function () {
      return this.users
      .filter(this.filterByName)
      .filter(this.filterByAge)
      .sort(this.orderBy);
    }
  }

It filters and sorts the users array by combining two filter functions and one comparator function :

methods: {
    filterByName : function(user) {
      // no search, don't filter : 
      if (this.searchName.length === 0) {
        return true;
      }

      return  (user.name.toLowerCase().indexOf(this.searchName.toLowerCase()) > -1);
    }, 
    filterByAge : function (user) {
      // no operator selected or no age typed, don't filter : 
      if (this.searchOperator.length === 0 || this.age.length === 0) {
        return true;
      }

      if (this.searchOperator === '>') {
        return (user.age > this.age); 
      } else  if (this.searchOperator === '<') {
        return (user.age < this.age);
      }      
    }, 
    orderBy : function (userA, userB) {
      let condition = (userA[this.sortKey] > userB[this.sortKey]);
      if (this.reverse) {
        return !condition;
      } else {
        return condition;
      }
    }
  },

Working snippet :

new Vue({
  el: '#demo',

  data: {
    sortKey: 'name',
    reverse: false,
    searchName: '',
    searchOperator: '',
    searchAge: '',
    columns: ['name', 'age'],
    newUser: {},
    search: "",
    name: "",
    age: "",

    users: [
      { name: 'John', age: 50 },
      { name: 'Jane', age: 22 },
      { name: 'Paul', age: 34 },
      { name: 'Kate', age: 15 },
      { name: 'Amanda', age: 65 },
      { name: 'Steve', age: 38 },
      { name: 'Keith', age: 21 },
      { name: 'Don', age: 50 },
      { name: 'Susan', age: 21 }
    ]
  },
  methods: {
    sortBy: function (sortKey) {
      this.reverse = (this.sortKey == sortKey) ? !this.reverse : false;

      this.sortKey = sortKey;
    }, 
    filterByName : function(user) {
      // no search, don't filter : 
      if (this.searchName.length === 0) {
        return true;
      }

      return  (user.name.toLowerCase().indexOf(this.searchName.toLowerCase()) > -1);
    }, 
    filterByAge : function (user) {
      // no operator selected or no age typed, don't filter : 
      if (this.searchOperator.length === 0 || this.age.length === 0) {
        return true;
      }

      if (this.searchOperator === '>') {
        return (user.age > this.age); 
      } else  if (this.searchOperator === '<') {
        return (user.age < this.age);
      }      
    }, 
    orderBy : function (userA, userB) {
      let condition = (userA[this.sortKey] > userB[this.sortKey]);
      if (this.reverse) {
        return !condition;
      } else {
        return condition;
      }
    }
  },
  computed: {
    filteredPersons: function () {
      return this.users
      .filter(this.filterByName)
      .filter(this.filterByAge)
      .sort(this.orderBy);
    }
  },  
});
body {
  margin: 2em 0;
}

a {
  font-weight: normal;
  color: blue;
}

a.active {
  font-weight: bold;
  color: black;
}
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"/> 
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<script src="index.js" defer></script>

</head>
<body>
<div id="demo" class="container">
  <div class="row">
    <div class="col-md-6">
      <input v-model="searchName" class="form-control" placeholder="Username to search">
    </div>
    <div class="col-md-1">
      <select class="form-control" v-model="searchOperator">
        <option value=">">></option>
        <option value="<"><</option>
      </select>
    </div>
    <div class="col-md-5">
      <input v-model="age" class="form-control" placeholder="Age" type="number">
    </div>
  </div>
  <table class="table table-striped">
    <thead>
      <tr>
        <th v-for="column in columns">
         <!-- <a href="#" v-on="click: sortBy(column)" >-->
         <!--  <a href="#"> -->
          <a href="#" v-on:click="sortBy(column)" v-bind:class="{active: sortKey == column}">
           
            <!--{{ column | capitalize }}-->
            {{column}}
          </a>
        </th>
      </tr>
    </thead>

    <tbody>
      <tr v-for="user in filteredPersons">
        <td>{{ user.name }}</td>
        <td>{{ user.age }}</td>
      </tr>
    </tbody>
  </table>
</div>
</body>
</html>
like image 164
Guillaume Georges Avatar answered Oct 27 '22 09:10

Guillaume Georges