In a VueJS component, I want to render the data which I receive from an API structured as shown below (array of objects).
const data = [
{
"firstName": "Nick",
"lastName": "Pappas",
"photo": "https://via.placeholder.com/150",
},
{
"firstName": "John",
"lastName": "Stamos",
"photo": "https://via.placeholder.com/150",
},
{
"firstName": "George",
"lastName": "Papadopoulos",
"photo": "https://via.placeholder.com/150",
}
]
My goal is to produce a "table-looking" layout with the significant requirement: every object isn't a row, it's a column.
<script src="https://cdn.tailwindcss.com"></script>
<div class="table">
<div class="photos table-row">
<div class="table-cell p-3">
photo1
</div>
<div class="table-cell p-3">
photo2
</div>
<div class="table-cell p-3">
photo3
</div>
</div>
<div class="first-names table-row">
<div class="table-cell p-3">
George
</div>
<div class="table-cell p-3">
Nick
</div>
<div class="table-cell p-3">
John
</div>
</div>
</table>
How could one generate something similar to the above while using the Vue template directives? My hints are:
const groupedByKey = {
"firstNames": ["Nick", "John", "George"],
"lastNames": ["Pappas", "Stamos", "Papadopoulos"]
"photos": ["...."]
}
flex-direction: column on each company container.
(The problem with this is it lacks all table properties with regards to element autosizing depending on the content of other elements of the row.)This of course could be achieved by having one separate loop for each property, but for performance and maintenance reasons this is something that I wish to avoid.
I will upvote and accept answers that provide lodash methods to group the data per key as shown in the snipped but ideally if a CSS/HTML only way (of course using the Vue template directives as much as possible) is possible, it would be preferred.
Merge all objects to a single object by spreading the array into _.mergeWith(), and concatenating the values using the customizer function:
const groupByKey = arr => _.mergeWith({}, ...arr, (
a = [], b = []) => a.concat(b)
)
const data = [{"firstName":"Nick","lastName":"Pappas","photo":"https://via.placeholder.com/150"},{"firstName":"John","lastName":"Stamos","photo":"https://via.placeholder.com/150"},{"firstName":"George","lastName":"Papadopoulos","photo":"https://via.placeholder.com/150"}]
const result = groupByKey(data)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
With Vanilla JS you can reduce the array to an object. On each iterate run the current object (o) through Object.entries(), and then iterate the entries with Array.forEach() and add them to the the relevant array. You can use Logical nullish assignment (??=) to init keys that don't exist yet.
const groupByKey = arr => arr.reduce((acc, o) => {
Object.entries(o)
.forEach(([k, v]) => {
(acc[k] ??= []).push(v)
})
return acc
}, {})
const data = [{"firstName":"Nick","lastName":"Pappas","photo":"https://via.placeholder.com/150"},{"firstName":"John","lastName":"Stamos","photo":"https://via.placeholder.com/150"},{"firstName":"George","lastName":"Papadopoulos","photo":"https://via.placeholder.com/150"}]
const result = groupByKey(data)
console.log(result)
Flexbox is a viable solution here, despite your concern about auto-sizing issues. (Feel free to point out those issues in my demo below)
You could render the list of data with v-for, where each iteration is a column:
<template>
<div class="user-table">
<div class="user-column" v-for="col in data">
<img class="photo" :src="col.photo" :alt="col.firstName">
<div class="first-name">{{ col.firstName }}</div>
</div>
</div>
</template>
Then use Flexbox to style .user-table and .user-column:
.user-table {
display: flex;
justify-content: space-around;
}
.user-column {
display: flex;
flex-direction: column;
}