vue 2 filter multiple array - javascript

Excuse me, my json data have two array.
I want to filter this json data(banner_img:['img']) with Vue.js.
But Analysis Json data is some problems..
Json data
[{"id":10,"banner":"AIR","banner_img":[{"id":1,"img":"air_1.png","banner_id":10},{"id":2,"img":"air_2.png","banner_id":10}]},
{"id":11,"banner":"HOT","banner_img":[{"id":3,"img":"hot_1.png","banner_id":11},{"id":4,"img":"hot_2.png","banner_id":11}]},
{"id":12,"banner":"NEW","banner_img":[{"id":5,"img":"new_1.png","banner_id":12},{"id":6,"img":"new_2.png","banner_id":12}]}]
Vue.js
var app = new Vue({
el: '#app',
data: {
banner:[],
search:'',
},
methods: {
getBannerData: function() {
axios.get('/case/ajax/33').then(response => {
this.banner = response.data.banner;
});
},
},
mounted: function() {
this.getBannerData();
},
computed: {
filteredList() {
return this.banner(value => {
return value.banner_img.filter(bannerImg => {
return bannerImg.img.toLowerCase().includes(this.search.toLowerCase());
});
})
}
}
});
HTML
<input type="text" name="ImgFilter" v-model="search">
<div v-for="value in filteredList">
<img v-for="imgs in value.banner_img" :src="imgs.img" height="100">
</div>
Then I try this filteredList
return value.banner_img.filter(bannerImg => {
return bannerImg.img.toLowerCase().includes(this.search.toLowerCase());
});
but is not work..
Please give me some advices~!

Try this one:
filterList:function()(
var that = this;
return this.banner.filter(function(item) {
return item.banner_img && item.banner_img.some(function(img) {
return img.img && img.img.toLowerCase() === that.search.toLowerCase();
});
});
)

Related

how to prevent a re-rendering of a variable that is not being used in the HTML of my vue.js component?

I am trying to recreate a real example of my code.
In my real code, this line is actually a component that will fetch an endpoint every few seconds, and fetch a random array of "n" length, myData it will contain these fetch.
<div v-for="item in addingData(myData)"> <!-- in My real code, "myData" should be the answer of an endpoint, is an setInterval, returns data like [{id:1},{id:2}] -->
{{ item.id }}
</div>
I am simulating that the response changes in myData with the help of setTimeOut
mounted() {
setTimeout(() => {
console.log('First data');
this.myData = [{ id: 3 }, { id: 2 }, { id: 1 }];
setTimeout(() => {
console.log('second data');
this.myData = [{ id: 4 }, { id: 4 }];
setTimeout(() => {
console.log('Third data');
this.myData = [];
}, 3000);
}, 3000);
}, 2000);
},
I am trying to make that every time I receive data in myData, the list of the concatenation of the received data is shown without having repeated data. That's why every time I receive data, that calls the function addingData(myData) that will do this data concatenation.
I'm using the function v-for="item in addingData(myData) and auxData is the variable that will do this concatenation.
why when there is new data, the addingData function is called 2 times and how can I prevent it?
in terms of performance this should be the output in the console.log:
what causes this re-rendering and how can I avoid it?
this is my live code:
https://stackblitz.com/edit/vue-l7gdpj?file=src%2FApp.vue
<template>
<div id="app">
<div v-for="item in addingData(myData)">
{{ item.id }}
</div>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue';
export default {
name: 'App',
data() {
return {
myData: [],
auxData: [],
};
},
mounted() {
setTimeout(() => {
console.log('First data');
this.myData = [{ id: 3 }, { id: 2 }, { id: 1 }];
setTimeout(() => {
console.log('second data');
this.myData = [{ id: 4 }, { id: 4 }];
setTimeout(() => {
console.log('Third data');
this.myData = [];
}, 3000);
}, 3000);
}, 2000);
},
methods: {
addingData(getDataFetch) {
console.log('Entering AddingData', getDataFetch);
if (getDataFetch.length !== 0) {
if (this.auxData.length === 0) {
//Adding initial data
this.auxData = getDataFetch;
} else {
//prevent duplicated values
getDataFetch.forEach((item) => {
const isNewItem = this.auxData.find((itemAux) => {
return item.id === itemAux.id;
});
if (!isNewItem) {
//adding new data
this.auxData.unshift(item);
}
});
}
} else {
//if there is not data, return []
return this.auxData;
}
},
},
};
</script>
As per my understanding, You want to combined the unique objects in to an array getting from multiple API calls and show them into the template using v-for. If Yes, You can achieve that by using computed property.
As you are updating the myData every time you are getting response, You can push the unique objects into a separate array and then return that array using a computed property.
Live Demo :
new Vue({
el: '#app',
data: {
combinedData: [],
myData: []
},
mounted() {
setTimeout(() => {
console.log('First data');
this.myData = [{ id: 3 }, { id: 2 }, { id: 1 }];
this.pushData(this.myData)
setTimeout(() => {
console.log('second data');
this.myData = [{ id: 4 }, { id: 4 }];
this.pushData(this.myData)
setTimeout(() => {
console.log('Third data');
this.myData = [];
this.pushData(this.myData)
}, 3000);
}, 3000);
}, 2000);
},
methods: {
pushData(data) {
data.forEach(obj => {
if (!JSON.stringify(this.combinedData).includes(JSON.stringify(obj))) {
this.combinedData.push(obj)
}
});
}
},
computed: {
finalData() {
return this.combinedData
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="item in finalData">
{{ item.id }}
</div>
</div>
in terms of performance this should be the output in the console.log
In terms of performance, you should use as few reactive data as possible, especially if your object has many properties. I would modify auxData directly.
this.addingData([{ id: 3 }, { id: 2 }, { id: 1 }]);
Simplified addingData
addingData(getDataFetch) {
// It's faster to get the id-s first
let itemDict = new Set(this.auxData.map((m) => m.id));
getDataFetch.forEach((item) => {
if (!itemDict.has(item.id)) {
this.auxData.unshift(item);
itemDict.add(item.id);
}
});
},
And iterate over it
<div v-for="item in auxData">
{{ item.id }}
</div>
Also watching object list can also cause performance issues. It should be used on primitive values.
Example on StackBlitz
Looks like you should be using v-for with auxData as that's what you're updating using the result of your API call (myData). As your API sends you new results, use a watcher to run a function whenever a new update is made to then also update auxData
updated stackblitz
watch: {
myData(newData, oldData) {
console.log('Entering AddingData', newData);
if (newData.length !== 0) {
if (this.auxData.length === 0) {
this.auxData = newData;
} else {
newData.forEach((item) => {
const isNewItem = this.auxData.find((itemAux) => {
return item.id === itemAux.id;
});
if (!isNewItem) {
this.auxData.unshift(item);
}
});
}
}
},
},
<div v-for="item in auxData">
{{ item.id }}
</div>

Vue data variable to methods and then to provide

I have issue to get some values from methods and want to parse to provide.
How I can solve the problem?
methods: {
onClickCategory: (value) => {
return (this.catId = value);
},
},
provide() {
return {
categoryId: this.value,
};
},
I get always categoryId:undefined
I found solution:
methods: {
onClickCategory(value) {
this.categoryId.value = value;
},
},
provide() {
this.catID = this.categoryId;
return {
catId: this.catID,
};
},
As Vue Guide highlights,
Note: the provide and inject bindings are NOT reactive. This is
intentional. However, if you pass down an observed object, properties
on that object do remain reactive.
So one solution is wrap your value into one observed object, like test2.value in below example:
Vue.config.productionTip = false
Vue.component('v-parent', {template: `
<div>
<h4>Example</h4>
<p>Not Working: <input v-model="test1"></p>
<p>Working: <input v-model="test2.value"></p>
<v-child></v-child>
</div>
`,
data () {
return {
test1: 'blabla1',
test2: {value: 'blabla2'}
}
},
provide () {
return {parent1: this.test1, parent2: this.test2}
}
}),
Vue.component('v-child', {
template: `<div><pre>{{parent1}}</pre><pre>{{parent2.value}}</pre></div>`,
inject: ['parent1', 'parent2']
})
new Vue({
el: '#app',
data() {
return {
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<div>
<v-parent/>
</div>
</div>

Vue : How to implement Table search

I have a simple search functionality on table.
But somehow its not working,
I should be be getting filtered rows on the table while searching.
Following is the code:
// Search Input
<div class="dv-header-search">
<input type="text" class="dv-header-input"
placeholder="Search"
v-model="query.search_input">
</div>
//Table row
<tr v-for="row in filteredRow">
<td v-for="(value, key) in row">{{value}}</td>
</tr>
data() {
return {
model: { data: [] },
columns: {},
query: {
search_input: ''
},
}
},
// Setting model after API call
.then(function(response) {
Vue.set(vm.$data, 'model', response.data.model)
})
computed: {
filteredRow: function(){
return this.model.data.filter((row) => {
return row;
});
}
}
Now the filteredRow calls on page load, What am i missing here.
```
filteredRow: function(){
return this.model.data.filter((row) => {
return row;
});
}
```
should be
```
filteredRow: function(){
return this.model.data.filter((row) => {
// containOrNot should return bool
return containOrNot(row, this.query.search_input)
});
}
```
filteredRow: function(){
return this.model.data.filter((row) => {
//i don't know you value key.. so just picking first property
for(var key in row){
return String(row[key]).indexOf(this.query.search_input);
}
});
}

How to structure vue.js app so I can access ajax request data from computed property on page load

I have the following code (below) that lets a user search data in an array. I want to replace the data property with data from an api and I don't know the proper way to structure a vue.js app so the methods have access to ajax data that is called on page load.
I know I use the axios library to call the data.
Vue.axios.get('https://jsonplaceholder.typicode.com/posts/1').then((response) => {
console.log(response.data)
})
MY CODE
https://jsfiddle.net/bny191f7/1/
Vue.js code
new Vue({
el: '#app',
data: {
searchString: "",
users: [{ //____________I want to replace this data with api data
"name": "Bob"
},
{
"name": "Angel"
},
{
"name": "Whatever"
}
]
},
computed: {
filterUsers: function() { //___________And insure this has access to it
//___________so the app continues to work
var users_array = this.users,
searchString = this.searchString;
if (!searchString) {
return users_array;
}
searchString = searchString.trim().toLowerCase();
users_array = users_array.filter(function(item) {
if (item.name.toLowerCase().indexOf(searchString) !== -1) {
return item;
}
})
return users_array;;
}
}
});
HTML
<form id="app" v-cloak>
<input type="text" v-model="searchString" placeholder="Enter your search terms" />
<ul>
<li v-for="user in filterUsers">
<p>{{user.name}}</p>
</li>
</ul>
I figured it out.
VUE
new Vue({
el: '#app',
data: {
searchString: "",
users: undefined
},
mounted: function () {
Vue.axios.get('https://jsonplaceholder.typicode.com/posts')
.then(response => {
console.log(response);
this.users = response.data;
console.log(this.users);
})
.catch(function (error) {
console.log(error);
});
},
computed: {
filterUsers: function () {
var users_array = this.users,
searchString = this.searchString;
if(!searchString){
return users_array;
}
searchString = searchString.trim().toLowerCase();
users_array = users_array.filter(function(item){
if(item.title.toLowerCase().indexOf(searchString) !== -1){
return item;
}
})
return users_array;;
}
}
});
HTML
<form id="app" v-cloak>
<input type="text" v-model="searchString" placeholder="Enter your search terms" />
<ul>
<li v-for="user in filterUsers">
<p>{{user.title}}</p>
</li>
</ul>
</form>

Javascript get data through methods

I have been trying to get these piece of code to work but I cannot find the right solution. Please can someone tell me why this works (loads data on load) but new records are not shown automatically.
<script>
Vue.component('comments',{
template: '#comment-vue-template',
data:() => {
return {
comments: []
}
},
created: function(comments) {
this.$http.get('/comments')
.then(response => {
this.comments = response.body
});
setTimeout(1000);
},
methods: {
getComments: function(comments) {
this.$http.get('/comments')
then(response => {
this.comments = response.body
})
},
},
});
new Vue({
el:'#app',
});
</script>
and this code below does not work at all :-
<script>
Vue.component('comments',{
template: '#comment-vue-template',
data:() => {
return {
comments: []
}
},
created: function(comments) {
this.getComments();
},
methods: {
getComments: function(comments) {
this.$http.get('/comments')
then(response => {
this.comments = response.body
});
setTimeout(this.getComments,1000);
},
},
});
new Vue({
el:'#app',
});
</script>
Thanks in advance
Found my mistake
<script>
Vue.component('comments',{
template: '#comment-vue-template',
data:() => {
return {
comments: []
}
},
created: function() {
this.getComments();
},
methods: {
getComments() {
this.$http.get('/comments').then(response => {
this.comments = response.body
});
setTimeout(this.getComments,1000);
}
}
});
new Vue({
el:'#app',
});
</script>

Categories