Результаты пустого фильтра Vue.js
В Vue я должен фильтровать некоторые данные:
<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>
Как я могу обнаружить пустой результат фильтра и отобразить соответствующее сообщение пользователю?
ИЗМЕНИТЬ
В настоящее время я делаю следующее, которое, как я считаю, является взломанным обходным путем:
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
});
}
})
Ответы
Ответ 1
Vue 2.x(Обновление)
В Vue теперь могут использоваться только фильтры 2.x, как говорят docs, внутри интерполяции текста:
Фильтры Vue 2.x могут использоваться только внутри привязок усов. Чтобы добиться такого же поведения внутри привязок директив, вы должны использовать Computed properties.
Вы можете добиться такого же поведения с помощью встроенного метода filter
JavaScript и вычислимого свойства.
<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(исходный ответ)
На данный момент существует два способа. Во всех случаях шаблон может выглядеть одинаково.
<input v-model="searchQuery">
<span v-if="!filteredItems.length">No results.</span>
<ul>
<li v-for="item in filteredItems"></li>
</ul>
filterBy
Исходный метод filterBy
доступен через $options
.
computed: {
filteredItems: function () {
return this.$options.filters.filterBy(this.items, this.searchQuery);
}
}
$Eval
Немного более чистый подход. Eval выражение, как вы бы сделать внутри вашего шаблона.
computed: {
filteredItems: function () {
return this.$eval('items | filterBy searchQuery');
}
}
Ответ 2
В HTML:
<input v-model="search">
<h4 v-if="!filteredPhotos.length">No results</h4>
<ul>
<li v-for="photo in filteredPhotos">
<img :src="photo.src" :alt="photo.name">
</li>
</ul>
В JS вам нужно использовать вычисленные свойства следующим образом:
computed: {
filteredPhotos: function () {
return this.photos.filter(function(photo){
return photo.name.indexOf(this.search) > -1;
}.bind(this));
}
}
Демо: http://jsfiddle.net/crswll/Lr9r2kfv/37/
Ответ 3
Это будет работать только с Vue 1.0, даже тогда вы должны просто использовать вычисленное свойство. Я оставлю этот ответ здесь на всякий случай.
Вы можете использовать vm.$eval
и вычисленное свойство для этого.
computed: {
filteredItems: function () {
return this.$eval('items | filterBy searchQuery');
}
}
и используйте что-то вроде
<div v-if="filteredItems.length">
<div v-for="item in filteredItems">
{{ item.name }}
</div>
</div>
<div v-else>
No results found!
</div>
Ответ 4
Решение HTML/CSS (на всякий случай, если вы все еще пытаетесь исправить его через 2 года)
/* all list items are visible */
ul.that-list li { display: block; }
/* ...exept last one*/
ul.that-list li:last-child { display: none; }
/* but if last one is also first one ... means the only one */
ul.that-list li:first-child { display: block; }
<h2>List with items</h2>
<ul class="that-list">
<!-- here is your v-for with any filters you want -->
<li>1 - Item is here</li>
<li>2 - Another One Here</li>
<li>3 - And anothe one</li>
<!-- this is your message -->
<li>(!message) There is no items... sorry</li>
</ul>
<h2>Empty</h2>
<ul class="that-list">
<!-- v-for with no rendered items :c -->
<li>(!message) There is no items... sorry</li>
</ul>