Sometimes data coming from the server that you want to display as a data table is not flat.
data () {
return {
tableData: [
{
id: 1,
name: 'fred',
boss: {
id: 2,
name: 'bossman'
}
},
...
]
Now, in a column configuration, there's no way to identify boss.name as the data for a column. i.e., something like,
id name bossName
-- ----- --------
1 fred bossman
The work-arounds I can think of:
Change the shape of what comes from the server (you might not have control of the server, so this one isn't always available).
Flatten the data by using a computed property to transform the hierarchical structure to a flat one. This isn't so bad, but is probably not a great idea when the data set starts getting large.
import _ from 'lodash
tableData: function () {
return _.map(this.employees, (employee) => {
return {id: employee.id, name: employee.name, bossName: employee.boss.name}
})
}
This seems to work at first blush, but I'm not certain it would hold up in all the data table use-cases like changing the sort or applying filters.
Perhaps it could look like,
columns: [
{
label: 'bossName',
field: 'boss.name',
...
I'd also be satisfied with a workaround that didn't involve duplication of the entire data source array. Perhaps one exists using a function in place of the field name, but I can't think of it.
Another workaround, even solution, perhaps...
This came from the MAPT video course by Peter van Meijgaard
https://www.packtpub.com/mapt/video/web_development/9781788291613
class BaseTransformer {
static fetchCollection (items) {
return items.map(item => this.fetch(item))
}
static sendCollection (items) {
return items.map(item => this.send(item))
}
}
class EmployeeTransformer extends BaseTransformer {
static fetch(employee) {
return {
id: employee.id,
name: employee.name,
bossId: employee.boss.id,
bossName: employee.boss.name
}
}
static send(employee) {
// ...
}
}
Then in the API call, filter the fetched data through the transformer before putting it into the vuex store.
// in vuex store actions...
export const list = ({commit}) => {
proxy.list()
.then((response) => {
const data = {
employees: EmployeeTransformer.fetchCollection(response)
}
commit(types.RECEIVE_EMPLOYEES, data)
})
}
Will make this possible with the revamp of QDataTable
Another workaround, currently used by me:
<q-data-table :data="tableData" ...>
<template slot="col-boss" scope="cell">
<span>{{ cell.data.name }}</span>
</template>
</q-data-table>
Closing as code is ready in v0.15 datatable revamp.
Just to update this so everyone is clear what now can be done.
Use obj => obj.some.nested.prop in your field property for the column. So, for Kirk's example above, it would be:
columns: [
{
label: 'bossName',
name: 'The Boss'.
field: row => row.boss.name, // corrected see below!
...
Scott
I believe it should be:
field: row => row.boss.name,
This will return 'bossman' instead of 'fred'.
E.g.:
<template>
<div>
<q-table
title="Title"
:data="tableData"
:columns="columns"
row-key="id"
dense
>
<q-tr slot="body" slot-scope="props" :props="props" class="cursor-pointer">
<q-td v-for="col in props.cols" :key="col.name" :props="props">
<a>{{ col.value.name }}</a>
</q-td>
</q-tr>
</q-table>
</div>
</template>
<script>
export default {
// name: 'ComponentName',
data () {
return {
tableData: [
{
id: 1,
nested: {
id: 2,
name: 'Name inside nested object'
}
}
],
columns: [
{ name: 'nested', label: 'Nested objects', field: row => row.nested }
]
}
}
}
</script>
@stefanvanherwijnen - Correct! I was testing to see if anyone was awake! You passed! LOL! 😄
Just kidding. 😉
Here is a fiddle to show the nested data and getting values out of it correctly.
https://jsfiddle.net/smolinari/ednwy63t/
Scott
Any clue how I can set the nested property dynamically?
If I set:
field: row => row[variable]
The field variable is set to:
function field(row) { return row[variable]
Where as it should be the value (string) of the variable (so if variable is 'boss', it should be return row['boss']).
I don't think that is possible. Maybe someone with more knowledge might know better.
My suggestion would be to set up a generic data structure and remap your data to fit it.
Scott
Thanks.
You are right, it seems to be impossible without using eval() or new Function().
What works is this:
var func = new Function('return function field(row){ return row[\'' + variable + '\']}')
field: func()
However, ESLint tells you not to use new Function so you have to set 'no-new-func': 0.
... I have just tried setting field: variable again and it now seems to work fine :sob: .
I think the key is to set the Object as the field variable and use custom QTr and QTd to extract the values out of the nested object.
I ended up getting following error when I use field: row => row.createdBy.email
My code looks like as below
columns: [
{
label: 'createdBy',
name: 'The Boss'.
field: row =>row.createdBy.email
My data comes dynamically from DB and it is getting the data correctly.
Please help with this.
@sachingk This sounds like a standard vue iteration warning -- what are you using for the :key in the v-for loop that renders your columns?
@sachingk Based on the vue warning, your email is either object or array
You are right.
I fixed my for loop. Now it works fine.
On Mon, 20 Jul, 2020, 6:06 AM Kirk Stork, notifications@github.com wrote:
@sachingk https://github.com/sachingk This sounds like a standard vue
iteration warning -- what are you using for the :key in the v-for loop that
defines your columns?—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/quasarframework/quasar/issues/821#issuecomment-660737269,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAH75R3NZNQBVHBSMYU3YMTR4OGQXANCNFSM4DX3VI4A
.
Most helpful comment
I believe it should be:
field: row => row.boss.name,This will return 'bossman' instead of 'fred'.
E.g.: