1👍
It appears that your goal is to display table columns depending on the checked status of a data property that represents the column. If so, then again, I’d make all data reactive, and then I’d use Vue’s computed properties to help us decide what to show.
So, assuming that this represents a simplification of the columns data:
const items = ref([
{ id: 0, text: 'date', checked: true },
{ id: 1, text: 'name', checked: false },
{ id: 2, text: 'day', checked: false },
{ id: 3, text: 'reason', checked: true },
{ id: 4, text: 'comment', checked: true },
]);
Then we can give the second component, Overview.vue, a props called "columns":
const props = defineProps(['columns']);
And then a computed property called activeColumns
that holds only the "checked" column objects:
const activeColumns = computed(() => {
return props.columns.filter((c) => c.checked);
});
Then let’s assume that the data to display in the table looks something like this (again, a simplification):
const tableData = ref([
{
"id": 1,
"date": "2/1/2023",
"name": "SNAFU",
"day": "Wednesday",
"reason": "Whatever 1",
"comment": "Comment 1"
},
{
"id": 2,
"date": "2/2/2023",
"name": "FUBAR",
"day": "Thurday",
"reason": "Whatever 2",
"comment": "Comment 2"
},
//.... more data here
Then we can use the computed property, activeColumns
in a v-for to decide which data to show:
<tbody>
<tr v-for="row in tableData" :key="row.id">
<td v-for="col in activeColumns" :key="col.id">{{ row[col.text] }}</td>
</tr>
</tbody>
You also mention,
In each div I have different components, so I can not loop over them with a v-for.
But this isn’t necessarily true since you can put your components into an array or an object and use dynamic components to allow you to loop over them:
// components that show the related table headers
import Date from './Date.vue';
import Name from './Name.vue';
import Day from './Day.vue';
import Reason from './Reason.vue';
import Comment from './Comment.vue';
const props = defineProps(['columns']);
const activeColumns = computed(() => {
return props.columns.filter((c) => c.checked);
});
// an object that holds all the table headers
const columnHeaders = ref({
'date': Date,
'name': Name,
'day': Day,
'reason': Reason,
'comment': Comment
});
Displayed as dynamic components:
<thead>
<tr>
<th v-for="col in activeColumns" :key="col.id">
<component :is="columnHeaders[col.text]"></component>
</th>
</tr>
</thead>
For example:
App.vue
<template>
<h2>Columns To Display</h2>
<div v-for="(item, index) in items">
<label for="item.id">
<input type="checkbox" v-model="item.checked" :value="item.id" :name="item.id" />
{{ item.text }}
</label>
</div>
<hr>
<Overview :columns="items"></Overview>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import Overview from './Overview.vue';
const items = ref([
{ id: 0, text: 'date', checked: true },
{ id: 1, text: 'name', checked: false },
{ id: 2, text: 'day', checked: false },
{ id: 3, text: 'reason', checked: true },
{ id: 4, text: 'comment', checked: true },
]);
</script>
and Overview.vue
<template>
<h2>
Overview
</h2>
<table>
<thead>
<tr>
<th v-for="col in activeColumns" :key="col.id">
<component :is="columnHeaders[col.text]"></component>
</th>
</tr>
</thead>
<tbody>
<tr v-for="row in tableData" :key="row.id">
<td v-for="col in activeColumns" :key="col.id">{{ row[col.text] }}</td>
</tr>
</tbody>
</table>
</template>
<script lang="ts" setup>
import { ref, computed, defineProps } from 'vue';
import Date from './Date.vue';
import Name from './Name.vue';
import Day from './Day.vue';
import Reason from './Reason.vue';
import Comment from './Comment.vue';
const props = defineProps(['columns']);
const activeColumns = computed(() => {
return props.columns.filter((c) => c.checked);
});
const columnHeaders = ref({
'date': Date,
'name': Name,
'day': Day,
'reason': Reason,
'comment': Comment
});
const tableData = ref([
{
"id": 1,
"date": "2/1/2023",
"name": "SNAFU",
"day": "Wednesday",
"reason": "Lorem ipsum",
"comment": "dolor sit amet, consectetur adipiscing elit"
},
{
"id": 2,
"date": "2/2/2023",
"name": "FUBAR",
"day": "Thurday",
"reason": "Ut enim",
"comment": "ad minim veniam, quis nostrud exercitation"
},
{
"id": 3,
"date": "2/3/2023",
"name": "BUZBAF",
"day": "Friday",
"reason": "Duis aute irure",
"comment": "dolor in reprehenderit in voluptate velit esse cillum dolore"
},
{
"id": 4,
"date": "2/4/2023",
"name": "FOO",
"day": "Saturday",
"reason": "Excepteur sint occaecat",
"comment": "cupidatat non proident, sunt in culpa qui officia"
},
{
"id": 5,
"date": "2/5/2023",
"name": "BAR",
"day": "Sunday",
"reason": "Sed ut perspiciatis",
"comment": "unde omnis iste natus error sit voluptatem accusantium doloremque laudantium"
}
]);
</script>
<style scoped>
table {
border-collapse: collapse;
border: 1px solid #FF0000;
}
table td,
th {
border: 1px solid #FF0000;
padding: 2px 10px;
}
</style>
For the array of components used as table headers:
Date.vue
<template>
Date
</template>
Name.vue
<template>
Name
</template>
Day.vue
<template>
Day
</template>
Reason.vue
<template>
Reason
</template>
Comment.vue
<template>
Comment
</template>
-2👍
You should change the JSON object.
const activeDivs = {
date: { id: 0, text: "date", checked: true },
name: { id: 1, text: "name", checked: false },
day: { id: 2, text: "day", checked: false },
time: { id: 3, text: "time", checked: false },
created: { id: 4, text: "created", checked: false },
reason: { id: 5, text: "reason", checked: true },
comment: { id: 6, text: "comment", checked: true },
};
if you can’t change the JSON structure then use find method to access single object.
found = activeDivs.find((element) => element.text == 'date');
or you can use computed to turn your array to desired object.