Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue.js empty filter results

Tags:

vue.js

In Vue, I have to filter through some data:

<input v-model="search">
<ul>
    <li v-repeat="photo in photos | filterBy search in 'name'">
        <img src="{{ photo.src }}" alt="{{ photo.name }}">
    </li>
    <li v-if="!photos.length">
        No results, sorry!
    </li>
</ul>

How can I detect empty filter results and display an appropriate message to the user?

EDIT

I am currently doing the following which I feel is a hacky workaround:

HTML:

<input v-model="search">
<ul>
    <li v-repeat="photo in photos">
        <img src="{{ photo.src }}" alt="{{ photo.name }}">
    </li>
    <li v-if="!photos.length">
        No results, sorry!
    </li>
</ul>

Javascript:

var v = new Vue({
    data: {
        allPhotos: [...],
        photos: [],
        search: '',
    },
    ready: function () {
        var filter = Vue.filter('filterBy');
        var self = this;
        this.$watch('search', function () {
            self.photos = filter(self.allPhotos, self.search, 'name');
        }, {
            immediate: true
        });
    }
})
like image 568
Andrew Willis Avatar asked Sep 23 '15 15:09

Andrew Willis


1 Answers

Vue 2.x (Update)

In Vue 2.x filters can now only be used, as docs say, inside text interpolations:

Vue 2.x filters can only be used inside mustache bindings. To achieve the same behavior inside directive bindings, you should use Computed properties instead.

You can achieve same behavior with JavaScript built-in filter method and computed property.

<input v-model="searchQuery">

<span v-if="!filteredItems.length">No results.</span>

<ul>
    <li v-for="item in filteredItems"></li>
</ul>
computed: {
  filteredItems: function () {
    var self = this;
    return self.items.filter(function (item) {
      return item.indexOf(self.searchQuery) !== -1;
    })
  }
}

Vue 1.x (Original Answer)

There are two ways at the moment. In all cases, template can look the same.

<input v-model="searchQuery">

<span v-if="!filteredItems.length">No results.</span>

<ul>
    <li v-for="item in filteredItems"></li>
</ul>

filterBy

Original filterBy method accessed via $options.

computed: {
    filteredItems: function () {
        return this.$options.filters.filterBy(this.items, this.searchQuery);
    }
}

$eval

A little bit cleaner approach. Eval expression like you would do inside your template.

computed: {
  filteredItems: function () {
    return this.$eval('items | filterBy searchQuery');
  }
}
like image 197
Jędrzej Chałubek Avatar answered Oct 06 '22 19:10

Jędrzej Chałubek