theflucs
theflucs

Reputation: 227

VUEJS Display nested object in <b-table> VUE-BOOTSTRAP

I have an array of objects (users) gotten by an api request. Its structure is something like this:

api response: (5) [{…}, {…}, {…}, {…}, {…}]

Inside this array, the objects are like this:

0: {
   user_address_string: ('Street 1')
   id: (3)
   avatar: (img')
   ...
   user: {
     id: 1
     first_name: 'Lucas'
     last_name: 'Smith'
   }
},
1: {...},
2: {...},
....
]

It is just a sample just to show you the structure. As you can see, among its properties there's another object named user{}. I need to display only the properties contained in this object. I would like to keep the structure of the table I was using before I got this new api (which didn't have objects as properties).

<b-table
  responsive
  v-if="users && users.length > 0"
  :fields="fields"
  :items="users"
>

The template should be something like this:

<template slot-scope="data">
   {{ data.item.user }}
</template> 

data.item should be the single user in the users array of objects, and with .user I should be able to access the properties of its object property user. (Going further data.item.user.first_name, etc, to access the single properties in it). What am I missing? Nothing is rendered on the screen. No errors in the console though. In the script I have:

users: [],
fields: [
      { key: 'id', label: 'ID'},
      { key: 'name', label: 'Name' }
]

So, how should I write the template for displaying the nested object’s properties? Also, the directive v-if="users && users.length > 0" in the b-table should still work, right? It is still an array, but of objects this time. Please correct me if I am wrong. Thank you

Upvotes: 3

Views: 6068

Answers (4)

Jonathan Arias
Jonathan Arias

Reputation: 590

An easy way to do it is by using a formatter in fields definition:

data() {
    return {
       fields: [
          {
            key: "avg_score",
            label: this.$t("avgScore"),
            sortable: true,
            sortByFormatted: true,
            formatter: (value, key, item) => item.stats.avg_score?.text 
          },
       ],
       items: [...your item list]
    }
}

And in the template:

<b-table :items="items" :fields="fields"></b-table>

The formatter will print the specified key or value automatically.

Upvotes: 0

theflucs
theflucs

Reputation: 227

As @Troy Morehouse suggested, I just needed to redefine the fields definition as

{ key: 'user.first_name', label: 'First name' } 

**UPDATE after @artworkjpm comment: The HTML code should be something like this:

<b-table
   v-if="users && users.length > 0 && !isLoading"
   id="table-transition-userList"
   :key="users.id"
   responsive
   :tbody-tr-class="userStatus"
   :tbody-transition-props="transProps"
   :fields="fields"
   :items="users"
>
   <template
      v-slot:cell(fullName)="data"
   >
      {{ data.item.user.first_name }} {{ data.item.user.last_name }}
   </template>
   <template
      v-slot:cell(buttons)="data"
   >
      <b-button
         v-b-tooltip.hover
         title="See plan"
         class="btn-plan p2"
         variant="primary"
         :disabled="!data.item.user.is_active"
         @click.prevent="seePlan(data.item), selectUser(data.item)"
      >
         <span class="svg-container">
            <svg-icon icon-class="route" />
         </span>
      </b-button>
   </template>
</b-table>

**Minor change in fields, but the concept is the same:

fields: [
        { key: 'fullName', label: 'User' },
        { key: 'buttons', label: 'Operations' }
      ],

Hope it helps. xx

Upvotes: 1

Troy Morehouse
Troy Morehouse

Reputation: 5435

You can specify nested field keys in dotted notation:

export default {
  data() {
  return {
    users: [],
    fields: [
      { key: 'id', label: 'ID'},
      { key: 'user.first_name', label: 'First Name' },
      { key: 'user.last_name', label: 'Last Name' }
    ]
  }
}

Upvotes: 4

Michael
Michael

Reputation: 5048

Whereever you get your data, you can extract the property you want and save locally in this case it would look something like this:

data()
  return {
    users: []
    }
    methods: {
     async getUsersFromApi(){
        const { data: {users }} = await axios.get(...)
        users.map(user => {
           this.users.push(user.user)
        }

Upvotes: 0

Related Questions