Only use certain fields from json in nuxt app - vue.js

By using asyncdata and axios I am grabbing a json object from a database called Knack.
Working great however the whole response is huge and in some pages I’m only using say 10 fields from sometimes 50+.
So I’m grabbing records from knack and then using v-for to loop through and output 10 of the 50+ fields from say 200 records.
By looking in console I can see the whole json object.
Is there a way to get the json object as I am and rather than returning it all, loop through and create a smaller object with the fields I need and returning that to then do a v-for in my template? Basically resulting in only the required fields being visible in console and to the public?
Thanks so much if someone can help with a code sample.

You can do it this way.
Sample data model
data() {
return {
// Required fields to filter data
requiredFields: ["name", "phone", "email"],
fields: {
name: "Wade Mckenzie",
phone: "1-278-483-8300",
email: "ac.mattis.velit#magnisdisparturient.net",
address: "971-2324 Id, Av.",
list: 7,
country: "Australia",
postalZip: "422625",
region: "Campania",
text: "malesuada augue ut lacus. Nulla tincidunt, neque vitae semper egestas,",
numberrange: 5,
currency: "$9.91",
alphanumeric: "TXQ00DEL5RP",
},
};
}
Computed prop
computed: {
filteredData() {
// Create an empty object
let requiredData = {};
// Loop over the entries
for (const [key, value] of Object.entries(this.data)) {
// Check if the property is a required field
if (this.requiredFields.includes(key)) {
requiredData[key] = value;
}
}
return requiredData;
},
}
Template
<div v-for="(value, name) in filteredData" :key="name">
{{ name }}: {{ value }}
</div>
You can check out the working example.

You can do that in a computed property.
computed(){
getCustomObject(){
let customObject = {};
for(let property in yourJsonObject){
if(property == 'the field you want'){
customObject[`${property}`] = yourJsonObject[property]
}
}
return customObject;
}
}
In this way you can get specific fields that you want. But you will have to specify them by placing || in the if statement.
In template you can simply render it like this: -
<div v-for="(item,key,index) in getCustomObject" :key="index">
//Render data...
</div>
Or if you just want a specific number of fields like 10 fields from 50, you can do it like this: -
computed(){
getCustomObject(){
let customObject = {};
Object.entries(yourJsonObject).forEach(([key,value],index) => {
if(index<10){
customObject[`${key}`] = value;
}
})
return customObject;
}
}

Related

Vue dynamic form elements in for loop

In a vue component I want to generate dynamic input elements in a for loop and bind them to the data.form element.
data() {
return {
form: {}
}
}
<b-form-checkbox v-model="form[key]['amount']" type="checkbox" :value="key"></b-form-checkbox>
How can I deal with this, what I tried:
form.amount[key] // is working, but not really the best data structure, and the array is populated with null values for each for loop entry on init ...
form[key]['amount'] // not working
// the working example I mentioned is structured this way
form: {
amount: [],
}
Maybe someone can help me with this ...
Simply define an empty array for the form fields, e.g. return { formFields: [] }. Then add as many values in this array as input fields you want to render on the screen:
<template>
<form>
<input v-for="(field,index) in formFields" :key="index" v-model="fields[index]" type="text">
</form>
</template>
<script>
export default
{
data()
{
return {
formFields: []
};
},
mounted()
{
for (let i = 1; i <= 10; i++) this.formFields.push('');
}
}
</script>
If you need different types of input fields - you will need to use array of objests instead of strings, and encode the field type as a property inside each of these objects.

Vue search while typing

I have search field and I wish to have the results in real-time,
I have no issue with returning data or showing data but I need a way to send input value to back-end while user is typing it.
Code
HTML
<el-input placeholder="Type something" v-model="search">
<i slot="prefix" class="el-input__icon el-icon-search"></i>
</el-input>
Script
data() {
return {
search: '' // getting data of input field
}
},
I've tried to compute it but it didn't return data
computed : {
searchSubmit: {
get: function () {
console.log(this.search);
}
}
},
Any idea?
For side effects as calling backend you can use Watchers.
watch: {
search(value) {
yourApiCall(value)
}
}

How to maintain original array sort order with Vue.js

I'm using v-for with Vue.js (v2.6.12) to display entries in an object e.g.
{
"12345": {
name: "foo",
isAccepted: true,
},
"56789": {
name: "bar",
isAccepted: false,
}
}
HTML:
<div v-for="item in sortMyItems(items)" v-bind:key="item.id">
<span>{{ item.name }}</span>
<span>{{ item.isAccepted }}</span>
</div>
Sort method in VM:
methods: {
sortMyItems: function(items) {
var accepted = [];
var rejected = [];
for (var id in items) {
var item = items[id];
if (item.isAccepted) {
accepted.push(item);
} else {
rejected.push(item);
}
}
return accepted.concat(rejected);
}
}
It's important to me to maintain the object structure of items in the model, which is why I'm doing it this way. The problem I have is that when the isAccepted property of any of the items in my data structure change, Vue re-renders the items that the sort order reflects the new ordering. I understand that this is a very useful feature of Vue, but in my case I really don't want this to happen. I want the sort order to be maintained the way it is after sortMyItems is first called. Is there a way to tell Vue to not monitor changes or just not re-render e.g. v-once
As far as I understood your question:
You could call sortMyItems(items) in the created Lifecycle Hook and store the result in a property of data.
Then, you can iterate over that property in your v-for:
export default {
data() {
return {
sortedData: [];
}
},
created() {
this.sortedData = sortMyItems(items)
}
}

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
})
}]