vuejs add filter to paginated list generated by json response - vuejs2

I´ve just started with Vue and stuck with a basic question. Following this tutorial I´m receiving posts as json. The list of post gets paginated
displayedPosts() calculates and returns shown posts per page
methods: {
...
paginate (posts) {
let page = this.page;
let perPage = this.perPage;
let from = (page * perPage) - perPage;
let to = (page * perPage);
return posts.slice(from, to);
},
...
computed: {
displayedPosts () {
return this.paginate(this.posts);
},
...
Then Template is bound to displayedPosts:
<div class="col-md-4" v-for="post in displayedPosts">
<div class="card mb-4 box-shadow post-cards">
...
Now I´d like to add an input to filter the whole list.
// template input
<input type="search" placeholder="Search..." autofocus v-model="search">
// method to filter model
computed: {
...
filteredItems () {
return this.posts.filter(item => {
return item.title.toLowerCase().indexOf(this.search.toLowerCase()) > -1
})
}
In summary, the pagination does only allow a certain amount of items per page. The filter should hide all list items and only show posts which contain given string.
In case my filter method is correct how would I bind filteredItems to the template for loop as this is already bound to displayesPosts()?
Thanks a lot for your help!

You can change displayedPosts:
computed: {
displayedPosts () {
return this.paginate(this.filteredItems);
},
filteredItems () {
return this.posts.filter(item => {
return item.title.toLowerCase().indexOf(this.search.toLowerCase()) > -1
})
}
}

Related

NuxtJs where to declare a computed property

How can i declare a computed property using Nuxt ? or the equivalent ?
I am using NuxtJs and trying to use a category filter.
I want to filter by unique categories, and i am getting this error message:
Cannot read property 'filter' of undefined
I trying to adapt to Nuxtjs the exemple i found in this pen : https://codepen.io/blakewatson/pen/xEXApK
I declare this computed property below, first at pages/index.vue and after into .nuxt/App.js
filteredStore: function() {
var vm = this;
var category = vm.selectedCategory;
if(category=== "All") {
return vm.stores;
} else {
return vm.stores.filter(function(stores) {
return stores.category === category;
});
}
}
And i try to apply the filter into this list of checkboxes :
<div class="columns is-multiline is-mobile">
<div class="column is-one-quarter" v-for="store in filteredStore" :key="store.id" :store="store">
<label class="checkbox">
<input type="checkbox" v-model="selectedCategory" :value="''+store.category">
{{store.category}}
</label>
</div>
</div>
I'm going to do some guessing at your code situation (based on the example you noted), so just let me know where I make an incorrect assumption. I would guess that something like the following could work for you... maybe you could provide additional details where I'm missing them.
With regards to your error Cannot read property 'filter' of undefined, that probably means your array of stores is undefined. I believe if you create the stores array as empty in the data section, you should at least have it available before your async call returns any results.
One possible thing to you can do to test if your filtering logic is working... is to uncomment the manually created data array that I've created below. It's like an inline test for your data structure and logic, removing the asynchronous retrieval of your data. This basically can check if the filter works without your API call. It would narrow down your issue at least.
export default {
data() {
return {
stores: [
// Let's assume you don't have any static stores to start on page load
// I've commented out what I'm guessing a possible data structure is
//
// Example possible stores in pre-created array
// { name: 'Zales', category: 'Jewelry', id: 1 },
// { name: 'Petco', category: 'Pet Shop', id: 2 },
// { name: 'Trip Advisor', category: 'Tourism', id: 3 },
// { name: 'Old Navy', category: 'Clothes', id: 4 }
],
selectedCategory: 'All'
}
},
computed: {
// Going to make some small js tweaks
filteredStores: () {
const vm = this;
const category = vm.selectedCategory;
if (category === "All") {
return vm.stores;
} else {
return vm.stores.filter(store => {
return store.category === category;
});
}
}
},
async asyncData({ $axios }) {
$axios
.$get('https://yourdomain.com/api/stores/some-criteria')
.then(response => {
this.stores = response.data;
})
.catch(err => {
// eslint-disable-next-line no-console
console.error('ERROR', err);
});
}
};
And then your HTML
<div class="columns is-multiline is-mobile">
<div class="column is-one-quarter" v-for="store in filteredStores" :key="store.id" :store="store">
<label class="checkbox">
<input type="checkbox" v-model="selectedCategory" :value="`${store.category || ''}`">
{{store.category}}
</label>
</div>
</div>
ANYWAY This is all just a big guess and what your scenario is, but I figured I'd try to help shape your question some so that you could get a more meaningful response. In general, I'd suggest trying to provide as much detail as you can about your question so that people really can see the bits and pieces where things might have gone astray.
Don't touch anything in .nuxt Someone noted that above in a comment, and it's very important. Essentially that whole directory is generated and any changes you make in it can be easily overwritten.

how to append multiple query parameters in url - NuxtJS

I am creating a nuxt ecommerce application. I have a situation where I have more than 10,000 items in a category and i want to create related filters for the products.
My question is how do i append url (add & remove query parameters) so that i can filter products.
I have tried something like this by adding a change event to !
<ul>
<li>
<b-form-checkbox #change="filterProduct">
<label class="ui__label_checkbox">Apple</label>
</b-form-checkbox>
</li>
<li >
<b-form-checkbox #change="filterProduct">
<label class="ui__label_checkbox">Mango</label>
</b-form-checkbox>
</li>
</ul>
methods:{
filterProduct() {
this.$router.push({ query: Object.assign({}, this.$route.query, { random: "query" }) });
},
}
This approach does append the url only once but removes the checked state of the checkbox which i don't want
I want similar to below everytime i click checkbox, it must retain the state of the checkbox at the same time append to the url
www.foobar.com/?first=1&second=12&third=5
Here's what you should do. First of all, you should all your filters state in data()
data() {
return {
filter: {
first: this.$route.query.first || null,
second: this.$route.query.second || null,
third: this.$route.query.third || null
}
}
}
Then you set up a watcher that fires when any filter changes, obviusly you need to v-model the inputs in your <template> to the fields in data()
watch() {
filter: {
handler(newFilters) {
const q = complexToQueryString({
...this.filter,
})
const path = `${this.$route.path}?${q}`
this.$router.push(path)
}
}
}
The complexToQueryString function is a thing of mine which removes null values from the query and also works for filters that are arrays. I did this because my API reads null as String 'null'.
const complexToQueryString = (object, parentNode = null) => {
const query = Object.entries(object).map((item) => {
const key = parentNode ? `${parentNode}[${item[0]}]` : item[0]
const value = item[1]
if (Array.isArray(value)) {
return arrayToQueryString(value, key)
} else if (value instanceof Object) {
return complexToQueryString(value, key)
} else if (item[1] !== undefined) {
return [
Array.isArray(item[0]) ? `${key}[]` : key,
encodeURIComponent(item[1]),
].join('=')
}
return ''
})
.filter(empty => empty)
.join('&')
return query
}
Now it should work, if you change the filter value then the data.filter.first changes the value, which fires the watcher, which updates the URL.
The best thing about this aproach is that now you can copy & paste the URL and the filter is exactly the same and returns the same result.
Your approach is almost correct, except that on page request, router-level You should append all the query parameters to route params.
Then asign those params to data inside Your filter page, and mutate them, also updating the query like You're doing now. This way You'll have query updated, and checkboxes wont lose state as they will depend on data, rather than on params.
routes: [{
path: '/path',
component: Component,
props: (route) => ({
filter1: route.query.filter1,
filter2: route.query.filter2,
filter3: route.query.filter3
})
}]

how to add a condition like a greater than equal to in filter search in vue js

Hi every one i am going to build a real-estate application
i want to add a condition in Bedrooms filter function like a "greater than equal "
Eg:- if i select 2 on Bedroom list i want to filter greater than equal 2 Bedrooms properties
How can i do this
export default {
data() {
return {
blogs: [],
minbed: this.$route.params.bed,
}
},
created() {
this.$http.get("https://test.json").then(function(data) {
console.log(data);
this.blogs = data.body;
});
},
computed: {
filteredList() {
const { blogs, search, UnitType } = this;
return this.blogs
.filter(blog => blog.Bedrooms.includes(this.minbed))
}
}
<select
v-model="minbed"
id="formInput202"
class="form-control"
value="MaxBedrooms"
>
<option>Max.Bedrooms</option>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>ST</option>
</select>
includes method is not working in this case. Only accepts string as the param (Ref-Link1).
The inline callback function will sort out this case,
Check the below code.
filteredList() {
const { blogs, search, UnitType } = this;
var MaxBedroomsVal = this.minbed;
return this.blogs.filter( function (blog) {
return blog.Bedrooms >= MaxBedroomsVal;
})
}
Ref: Link2

How do i get property of an object instead of whole object on v-model in vue.js

I had created an input form using html and given v-model="upCountryName", which is an empty array by default but if once name value clicked I had written function to fetch the data from django db using djangorestframework and I had got the data also but in input from v-model="upCountryName" I am getting data as [object Object].
So I written v-model="upCountryName.country" which actually I want to update but input form showing empty, how can I get country name instead of whole object.
----------
HTML --
<td v-on:click="up_country_form(c.id)">
<!--c.id is country.id i am getting from django db and passing it to the method up_country_form(id) in script-->
<center>
<p class="fas fa-pencil-alt"></p>
</center>
</td>
<input type="text" v-model='upCountryName.country' class="form-control">
----------
Vue.js
<script>
export default {
data () {
return {
upCountryName: []
};
},
methods: {
up_country_form (id) {
this.up_country_box = true;
this.$http.get('http://127.0.0.1:8000/getCountry/'+id)
.then((response) => {
this.upCountryName = response.data;
this.loading = false;
});
console.log(id);
this.add_country_box = false;
}
}
};
</script>
You have to make sure response.data is in form like { country: "Some Country Name" } then everything should work fine.
You can see the demo here.
Note: if you use upCountryName.country, the type of upCountryName should be Object not Array.
data () {
return {
upCountryName: {}
}
}

Vue.js 2 - $forceUpdate() on components doesn't refresh computed properties?

I'm not sure if I'm doing this right or wrong, but all the answers I seem to find how to update the dom for computed values...
I have this component:
Vue.component('bpmn-groups', {
props: ['groups', 'searchQuery'],
template: '#bpmn-groups',
computed: {
filteredGroups: function () {
var self = this;
return this.groups.filter(function(group) {
self.searchQuery = self.searchQuery || '';
return _.includes( group.name.toLowerCase(), self.searchQuery.toLowerCase() );
});
}
},
methods: {
clearFilter: function () {
this.searchQuery = '';
},
deleteGroup: function(group) {
Vue.http.delete('api/groups/'+group.id ).then(response => { // success callback
var index = this.groups.indexOf(group); // remove the deleted group
this.groups.splice(index, 1);
this.$forceUpdate(); // force update of the filtered list?
toastr.success('Schemų grupė <em>'+group.name+'</em> sėkmingai pašalinta.');
}, response => { // error callback
processErrors(response);
});
this.$forceUpdate();
},
},
});
And in the template I just have a simple v-for to go through filteredGroups:
<input v-model="searchQuery" type="text" placeholder="Search..." value="">
<div v-for="group in filteredGroups" class="item">...</div>
The deletion works fine, it removes it from groups property, however the filteredGroups value still has the full group, until I actually perform a search or somehow trigger something else...
How can I fix it so that the filteredGroup is updated once the group is updated?
Don't mutate a prop - they are not like data defined attributes. See this for more information:
https://v2.vuejs.org/v2/guide/components.html#One-Way-Data-Flow
Instead, as recommended in the link, declare a local data attribute that is initialized from the prop and mutate that.