I have two sets of arrays, one I'm using for the headers (columns) of a table, and the other for the rows of the table.
const headers = [
{
text: 'Dessert (100g serving)',
align: 'left',
sortable: false,
value: 'name',
visible: true
},
{ text: 'Calories', value: 'calories', visible: true },
{ text: 'Fat (g)', value: 'fat', visible: true },
{ text: 'Carbs (g)', value: 'carbs', visible: true },
{ text: 'Protein (g)', value: 'protein', visible: true },
{ text: 'Iron (%)', value: 'iron', visible: true }
]
const desserts = [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%'
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%'
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%'
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%'
}
]
What I'm trying to achieve is to give the user the ability to be able to decide which columns of the data they'd like to view in the table.
I'm using Vue.js, so my attempts have been to set out a collection of checkboxes, each is v-bind as a header from the headers collection.
I'm doing this using the following:
computed: {
filteredHeaders () {
return this.headers.filter(header => header.visible)
}
}
This works as expected, horrah! The table column headers change based on the columns selected with the checkboxes.
The bit I'm stuck on is trying to filter the row data (or desserts) based on the selected columns (or filteredHeaders).
I've tried the following:
computed: {
...
filteredItems () {
return this.desserts.filter(dessert => {
return this.filteredHeaders.some(header => {
return Object.keys(header).some(prop => {
return dessert[prop] != header[prop] && header.visible
})
})
})
}
}
Even though there are no errors being thrown, the result of filteredItems remains that of the original desserts and the properties that should be excluded (when visible gets set to false by the collection of checkboxes) are still being displayed.
I'm sure I'm close, but close doesn't get me that cigar (as the saying goes)!
1 Answer 1
This method should roughly achieve what you're looking for:
const headers = [{
text: "Dessert (100g serving)",
align: "left",
sortable: false,
value: "name",
visible: true
},
{
text: "Calories",
value: "calories",
visible: true
},
{
text: "Fat (g)",
value: "fat",
visible: true
},
{
text: "Carbs (g)",
value: "carbs",
visible: true
},
{
text: "Protein (g)",
value: "protein",
visible: true
},
{
text: "Iron (%)",
value: "iron",
visible: true
}
];
const desserts = [{
name: "Frozen Yogurt",
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: "1%"
},
{
name: "Ice cream sandwich",
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: "1%"
},
{
name: "Eclair",
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: "7%"
},
{
name: "Cupcake",
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: "8%"
}
];
const filterRows = (rows, headers) => {
// Map over the full list of rows to filter down
return rows.map(row => {
// Create a new row to return to avoid mutating
const filteredRow = {};
// Loop through each header and copy the row value corresponding to that header value
headers.forEach(header => {
filteredRow[header.value] = row[header.value];
});
// Return the copied and filtered row
return filteredRow;
});
};
console.log(filterRows(desserts, headers));
console.log(filterRows(desserts, [{
text: "Iron (%)",
value: "iron",
visible: true
}]));