Reputation: 516
I am using a tabbed interface built with Bootstrap-Vue. When clicking on one of these tabs I'm using v-for to render some data in an accordion/dropdown which is displayed as a grid.
Currently, I have a tab that shows all results which works fine when using the following (Note: prizesData is just where I'm storing response.data after I have called in with axios):
<div class="col-sm-12 col-md-6 col-lg-3 w-100 prize-dropdown-wrapper pb-5"
v-for="(prize, name, index) in prizesData"
:key="index"
>
<!--REMAINDER OF MARKUP GOES HERE-->
</div>
My JSON structure looks something like this, except I have 43 results in total. Every value in each object will change, but I want to use prizeType1Name and prizeType2Name to check if they contain the strings "CTW", "IW" or "OG":
{
"1": [
{
"prizeTitle": "",
"prizeImage": "",
"prizeFirstLineText": "",
"prizeType1": {
"Image": "",
"Line1": "",
"Line2": ""
},
"prizeType2": {
"Image": "",
"Line1": "",
"Line2": ""
},
"prizeTermsText": "",
"prizeType1Name": "CTW",
"prizeType2Name": ""
}
],
"2": [
{
"prizeTitle": "",
"prizeImage": "",
"prizeFirstLineText": "",
"prizeType1": {
"Image": "",
"Line1": "",
"Line2": ""
},
"prizeType2": {
"Image": "",
"Line1": "",
"Line2": ""
},
"prizeTermsText": "",
"prizeType1Name": "IW",
"prizeType2Name": ""
}
]
}
To access either of these values I am using:
this.prizesData[name][0].prizeType1
or this.prizesData[name][0].prizeType2
I'm having difficulty understanding how to filter my results. For example, if I click on the tab named (CTW), I want to show only the results that contain "CTW" in the JSON file. Or if the tab named "IW" is clicked then the results should be for the objects that contain "IW".
What I have tried:
Added filteredPrizes to store filtered prizes as an object to access later
data() {
return {
prizesData: {},
filteredPrizes: {},
};
}
I tried to use filter() on the existing prizesData object I received from the JSON file, I added this in the same method where I'm fetching the JSON file.
getPrizesInfo() {
const self = this;
//Get Error Validation JSON
axios
.get("/data/prizes.json")
.then(response => (this.prizesData = response.data));
this.filteredPrizes = this.prizesData.filter(prize =>
this.prizesData[name][0].prizeType1.includes("CTW")
);
}
What I'm expecting: I have 4 tabs, 1st one works fine (Shows all). The other 3 need to show only filtered results depending on if "CTW" "IW" or "OG" exist in either prizeType1Name or prizeType2Name.
Upvotes: 0
Views: 883
Reputation: 516
As @seantunwin suggested, I changed my JSON from an object to an array - required some tidying up and formatting but made life easier in the long run.
So my new structure now looks like this:
[
{
"id": 1,
"prizeTitle": "",
"prizeImage": "",
"prizeFirstLineText": "",
"prizeType1": {
"Image": "",
"Line1": "",
"Line2": ""
},
"prizeType2": {
"Image": "",
"Line1": "",
"Line2": ""
},
"prizeTermsText": "",
"prizeType1Name": "CTW",
"prizeType2Name": ""
}
]
I then used a computed property advised by @Our_Benefactors like this:
computed: {
filteredPrizesByQuery: function() {
*return* this.prizes.filter(prize => {
*return* (
prize.prizeType1Name.match(this.query) ||
prize.prizeType2Name.match(this.query)
);
});
}
}
I wrapped my code that I want to loop through using v-for and referenced the computed property:
<div
class="col-sm-12 col-md-6 col-lg-3 w-100 prize-dropdown-wrapper pb-5"
v-for="(prize, index) in filteredPrizesByQuery"
:key="index"
>
I set query as an empty string as default in data
data() {
*return* {
query: "",
prizes: [],
}
};
I added a click event on the tabs to change the query value, similar to @christiancarrillo answer
<b-tab title="IW" @click="query='IW'">
So now when I click on a tab the value changes to CTW, IW or OG, and the computed property checks through the values and returns the results that match the query.
Upvotes: 0
Reputation: 1778
filteredPrizes
be a comupted property// Inside data
filterCriteria: [
{ name: 'prizeType1Name', value: 'CTW' },
{ name: 'prizeType2Name', value: 'CTW' }
];
// Inside methods
getFilteredPrizes(prizes, criteria) {
selected = [];
Object.keys(prizes).forEach(a => {
criteria.forEach(b => {
if (prizes[a][0][b.name] === b.value && !selected.contains(prizes[a][0])) {
selected.push(prizes[a][0]);
}
});
});
return selected;
}
new Vue({
el: '#app',
data() {
return {
prizesData: {
"1": [
{
"prizeTitle": "",
"prizeImage": "",
"prizeFirstLineText": "",
"prizeType1": {
"Image": "",
"Line1": "",
"Line2": ""
},
"prizeType2": {
"Image": "",
"Line1": "",
"Line2": ""
},
"prizeTermsText": "",
"prizeType1Name": "CTW",
"prizeType2Name": ""
}
],
"2": [
{
"prizeTitle": "",
"prizeImage": "",
"prizeFirstLineText": "",
"prizeType1": {
"Image": "",
"Line1": "",
"Line2": ""
},
"prizeType2": {
"Image": "",
"Line1": "",
"Line2": ""
},
"prizeTermsText": "",
"prizeType1Name": "IW",
"prizeType2Name": ""
}
]
},
filterCriteria: [
{ name: 'prizeType1Name', value: 'CTW' },
{ name: 'prizeType2Name', value: 'CTW' }
]
}
},
computed: {
filteredPrizes() {
return this.getFilteredPrizes(this.prizesData, this.filterCriteria);
}
},
methods: {
getFilteredPrizes(prizes, criteria) {
selected = [];
Object.keys(prizes).forEach(a => {
criteria.forEach(b => {
if (prizes[a][0][b.name] === b.value && !selected.includes(prizes[a][0])) {
selected.push(prizes[a][0]);
}
});
});
return selected;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
<div id="app">
<h3>Filtered Prizes</h3>
<pre>{{ filteredPrizes }}</pre>
</div>
Upvotes: 1
Reputation: 2761
I am not sure I understood correctly, but you can try:
new Vue({
el: '#app',
data() {
return {
myData: {
prizeTitle: '',
prizeImage: '',
prizeFirstLineText: '',
prizeType1: {
Image: 'CTW',
Line1: 'CTW',
Line2: 'CTW'
},
prizeType2: {
Image: 'IW',
Line1: 'IW',
Line2: 'IW'
},
prizeTermsText: '',
prizeType1Name: 'CTW',
prizeType2Name: 'IW'
},
prizesData: {}
}
},
methods: {
filter (criteria) {
// getting keyName with value equals to criteria
const key =
Object.keys(this.myData)
.filter(key => this.myData[key] === criteria)
.pop().replace('Name', '')
this.prizesData = this.myData[key]
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
<div id="app">
<button @click="filter('CTW')">CTW</button>
<button @click="filter('IW')">IW</button>
<pre>{{ prizesData }}</pre>
</div>
Upvotes: 1