user1469734
user1469734

Reputation: 801

Vue computed Filter combining with Ordering

I have the following computed function so filter my houses based on a search input field. This works.

computed: {
    filtered: function() {
        var self = this;
        let searchTerm = (this.search || "").toLowerCase()
        if(this.houses) {
            return this.houses.filter(function(item) {
              let city = (item.city || "").toLowerCase()
              let street = (item.street || "").toLowerCase()
              return city.indexOf(searchTerm) > -1 || street.indexOf(searchTerm) > -1;
            })
        }
      }
  }

But how to implement ordering on City and Street also? Both asc and desc.

This is the table:

<input type="search" v-model="search" placeholder="Search for City OR Street" />
<table>
    <thead>
        <tr>
            <th @click="sortByStreet()">Street</th>
            <th @click="sortByCity()">City</th>
        </tr>
    </thead>
    <tbody>
        <tr v-for="house in filtered">
            <td>{{ house.street }}</td>
            <td>{{ house.city }}</td>
        </tr>
    </tbody>
</table>

How to fix it with the functions sortByStreet() and sortByCity()? Combined with the filter.

Upvotes: 1

Views: 2957

Answers (1)

Roy J
Roy J

Reputation: 43881

Your clicks should set a variable, call it sortBy, that the computed uses to determine how it sorts its results. When the variable changes, the computed will recompute.

new Vue({
  el: '#app',
  data: {
    search: 'Z-town',
    reverse: false,
    houses: [{
        street: 'First',
        city: 'Z-town'
      },
      {
        street: 'Second',
        city: 'A-town'
      },
      {
        street: 'First',
        city: 'A-town'
      },
      {
        street: 'Second',
        city: 'Z-town'
      }
    ],
    sortBy: 'street'
  },
  computed: {
    filtered: function() {
      const result = this.houses
        .filter(entry => [entry.street, entry.city].find(x => x === this.search))
        .sort((a, b) =>
          a[this.sortBy] < b[this.sortBy] ? -1 : a[this.sortBy] !== b[this.sortBy]
        );
        
      return this.reverse ? result.reverse() : result;
    }
  }
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="app">
  <input type="search" v-model="search" placeholder="Search for City OR Street" />
  <input type="checkbox" v-model="reverse"> Descending
  <table>
    <thead>
      <tr>
        <th @click="() => sortBy = 'street'">Street</th>
        <th @click="() => sortBy = 'city'">City</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="house in filtered">
        <td>{{ house.street }}</td>
        <td>{{ house.city }}</td>
      </tr>
    </tbody>
  </table>
</div>

Upvotes: 3

Related Questions