Search code examples
vue.jsmultidimensional-arraybootstrap-vuev-model

b-table items for deeply nested arrays


I have a b-table and within that b-table I use row.details to display some more information. In fact, the details are a sub-array of the overall array. Within the row.details I want to use another b-table to display all details. Eventually, I'll change some values of the subarray. To do so, I have to know the index of the current row that I look at in row.details. So this is my question: for my second b-table, how can I set the items this way, that I still have the row path from my initial b-table?

I was thinking of writing some function to store the row I'm currently in in a global variable and find that index in my second b-table items and continue the path then. But I was also wondering there might be an easier solution and to "hand over" the path from the initial b-table.

My data look like this:

rooms:
[
    {
        room0: "firstroom",
        details: [
            {detail0: ""},
            {detail1: [
                {subDetail0: ""},
                {subDetail1: ""}
            ]}
        ]
    },
    {
        room1: "secondroom",
        details: [
            {detail0: ""},
            {detail1: [
                {subDetail0: ""},
                {subDetail1: ""}
            ]}
        ]
    },
],
subDetailsHeader:
[
    {key: "details"},
    ...
]

And that's the structure of the bootstrap-vue html(using same items for both tables - which "kills" the path of the first table)

<b-table :items="rooms" :fields="roomsHeader" head-variant="light">
    <template #cell(actions)="row" >
        <button @click="row.toggleDetails()">Details</button>
    </template>

    <template v-slot:cell(selected)="row" >
        <b-table :items="rooms" :fields"subDetailsHeader">
            <template #cell(date)="row">
                {{ row.items }}
            </template>
        </b-table>
    </template>
</b-table>

{{ row.items }} now displays the details of all rooms whereas I only want do display the details of the selected room (that's why I say "killing the room path"). Actually, I'll have the same problem when I add the subDetails following the same (nested) scheme. Help or recommendations are highly appreciated since I'm quite new to programming :) thanks in advance!

// Edit 1:

The overall problem can be solved by using slots instead of items for the second- and third-level b-table

However, I still have problems displaying an array/object in the second-level b-table

Here's a data example:

rooms:
[    
    {
        "room": "HS004",
        "maxcapacity": 200,
        "selected": true,
        "period": {
            "2021-05-10": [
                {"slot_one": 200},
                {"slot_two": 200},
                {"slot_three": 200},
                {"slot_four": 200},
                {"slot_five": 200},
                {"slot_six": 200}
            ],
            "2021-05-11": [
                {"slot_one": 200},
                {"slot_two": 200},
                {"slot_three": 200},
                {"slot_four": 200},
                {"slot_five": 200},
                {"slot_six": 200}
            ],
            "2021-05-12": [
                {"slot_one": 200},
                {"slot_two": 200},
                {"slot_three": 200},
                {"slot_four": 200},
                {"slot_five": 200},
                {"slot_six": 200}
            ]
        }
    },
    {
        "room": "HS006",
        "maxcapacity": 200,
        "selected": true,
        "period": {
            "2021-05-10": [
                {"slot_one": 150},
                {"slot_two": 150},
                {"slot_three": 150},
                {"slot_four": 150},
                {"slot_five": 150},
                {"slot_six": 150}
            ],
            "2021-05-11": [
                {"slot_one": 200},
                {"slot_two": 200},
                {"slot_three": 200},
                {"slot_four": 0},
                {"slot_five": 0},
                {"slot_six": 0}
            ],
            "2021-05-12": [
                {"slot_one": 150},
                {"slot_two": 150},
                {"slot_three": 150},
                {"slot_four": 150},
                {"slot_five": 150},
                {"slot_six": 150}
            ]
        }
    }
]

my goal is, to display the objectNames of each row.item.period as a table and by clicking one date, open another detail section / modal where I can edit the six slots of this room/period pair. In order to store it with v-model, I need the whole path room.period.slot

Perhaps I'm missing another way. I could also display it as a list, but then I don't know how to assign the slot' of the selected list-item into the overall v-model

My initial post listed all periods of each room inthe second b-table. However, I only wanted to have the period of the selected room.

// Edit 2: I followed the idea from Iman and replaced my second b-table by a custom table. Now I can apply the v-model and assign the data correctly within my multidimensional array:

<b-table :items="roomTest" :fields="roomsHeader" head-variant="light">
  <template #cell(actions)="row">
      <b-button @click="row.toggleDetails()">Details</b-button>
  </template>
  <template v-slot:row-details="row">
    <table>
      <thead>
        <tr>
          <th>Datum</th>
          <th>08:00</th>
          <th>10:00</th>
          <th>12:00</th>
          <th>14:00</th>
          <th>16:00</th>
          <th>18:00</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(value, key) in row.item.period" :key="key">
          <td>
            {{ key }}
          </td>
          <td><input type="text" v-model="Object.values(value[0])"></td>
          <td><input type="text" v-model="Object.values(value[1])"></td>
          <td><input type="text" v-model="Object.values(value[2])"></td>
          <td><input type="text" v-model="Object.values(value[3])"></td>
          <td><input type="text" v-model="Object.values(value[4])"></td>
          <td><input type="text" v-model="Object.values(value[5])"></td>
        </tr>
      </tbody>
    </table>
  </template>
</b-table>

Solution

  • I tried to implement a 3 layer b-table with a toggle button in each row. You should take a quick look at row-details-support

    new Vue({
      el: '#app',
      data() {
        return {
          roomsHeader: [
            'room', 'actions'
          ],
          subRoomsHeader: [
            'sub_room', 'feature', 'actions'
          ],
          rooms: [{
            room: "firstroom",
            details: [{
              sub_room: "sub_room_1",
              feature: "F1",
              "details": [{
                sub_room_2: "sub room 2",
                feature_2: "F2"
              }]
    
            }]
          }, ],
        }
      },
      methods: {
        toggleDetails() {
    
        }
      }
    })
    <link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap@4.5.3/dist/css/bootstrap.min.css" />
    <link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap-vue@2.21.2/dist/bootstrap-vue.css" />
    
    <script src="https://unpkg.com/vue@2.6.12/dist/vue.min.js"></script>
    <script src="https://unpkg.com/bootstrap-vue@2.21.2/dist/bootstrap-vue.min.js"></script>
    
    <div id="app">
      <b-table :items="rooms" :fields="roomsHeader" head-variant="light">
        <template #cell(actions)="row">
          <b-button @click="row.toggleDetails()">Details</b-button>
        </template>
    
        <template v-slot:row-details="row">
          <b-table :items="row.item.details" :fields="subRoomsHeader">
            <template #cell(actions)="row">
              <b-button @click="row.toggleDetails()">Details</b-button>
            </template>
            <template v-slot:row-details="row">
              <b-table :items="row.item.details"></b-table>
            </template>
          </b-table>
        </template>
      </b-table>
    
    </div>