jim
jim

Reputation: 9138

bootstrap-vue toggle expand table row

This seems to remain unanswered so here is another attempt at a solution.

Currently in bootstrap-vue, I am rendering a b-table. I would like to improve this by having the ability to select a row and collapse/expand an extra div/row/etc to show further information.

In the below snippet you will see what I am trying. The problem is that I can't seem to get the expanded data to span the number of columns in the table. I have tried adding <tr><td colspan="6"></td></tr> but it doesn't seem to span like I would expect. Any workarounds for this? Thanks.

<b-table
    :items="case.cases"
    :fields="tableFields"
    head-variant="dark">
    <template
        slot="meta.status"
        slot-scope="data">
    <b-badge
        v-b-toggle.collapse1
        :variant="foobar"
        tag="h6">
        {{ data.value }}
    </b-badge>
    </template>
    <template
        slot="@id"
        slot-scope="data">
        <span
            v-b-toggle.collapse1>
            {{ data.value }}
        </span>
        <b-collapse id="collapse1">
            Collapse contents Here
        </b-collapse>
    </template>
</b-table>`

Upvotes: 5

Views: 14916

Answers (2)

Troy Morehouse
Troy Morehouse

Reputation: 5435

Sounds like you could use the Row Details slot:

If you would optionally like to display additional record information (such as columns not specified in the fields definition array), you can use the scoped slot row-details

<b-table :items="case.cases" :fields="tableFields" head-variant="dark">
  <template slot="meta.status" slot-scope="data">
    <b-button @click="data.toggleDetails">
        {{ data.value }}
    </b-button>
  </template>
  <template slot="row-details" slot-scope="data">
    <b-button @click="data.toggleDetails">
        {{ data.detailsShowing ? 'Hide' : 'Show'}} Details }}
    </b-button>
    <div>
       Details for row go here.
       data.item contains the row's (item) record data
       {{ data.item }}
    </div>
  </template>
</b-table>

There is a good example in the docs at https://bootstrap-vue.js.org/docs/components/table#row-details-support

Upvotes: 7

adlaws
adlaws

Reputation: 61

I (think) I had the same issue, and I came up with a solution which leverages the filtering functionality of the bootstrap-vue <b-table> to achieve the effect of expanding and collapsing rows.

There's a minimal example in a JSFiddle here:

https://jsfiddle.net/adlaws/mk4128dg/

Basically you provide a tree structure for the table like this:

[
    {
        columnA: 'John', columnB:'Smith', columnC:'75',
        children:
        [
            { columnA: 'Mary', columnB:'Symes', columnC:'46' },
            { columnA: 'Stan', columnB:'Jones', columnC:'42' },
            { columnA: 'Pat', columnB:'Black', columnC:'38' },
        ]
    }
]

The tree is then "flattened" out to rows which can be displayed in a table by the _flattenTreeStructure() method. During this process, the rows are also annotated with some extra properties to uniquely identify the row, store the depth of the row (used for indentation), the parent row of the row (if any) and whether or not the row is currently expanded.

Once this is done, the flattened structure can be handed to the <b-table> as it is just an array of rows - this is done via the computed property flattenedTree.

The main work now is done by the _filterFunction() method which provides custom filtering on the table. It works off the state of the expandedRowIndices property of the filterObj data item.

As the expand/collapse buttons are clicked, the row index (as populated during the flattening process) is inserted as a key into expandedRowIndices with a true or false indicating its current expanded state.

The _filterFunction() uses this to "filter out" rows which are not expanded, which results in the effect of expanding/collapsing a tree in the table.

OK, so it works (yay!), but...

  • it's not as flexible as the base <b-table>; if you want to show different columns of data, you'll need to do some work and to re-do the <template slot="???"> sections for the columns as required.
  • if you want to actually use filtering to filter the content (with a text search, for example) you'll need to extend the custom filter function to take this into account as well
  • sorting the data is not something I had to do for my use case, and I'm not sure how it would work in the context of a tree structure anyway - maintaining the tree's parent/child relationships while changing the order of the rows around would be... fun, and I suspect this would be a nice challenge to implement for someone who is not as time poor as me. ;)

Anyway, I hope this is of use to someone. I'm reasonably new to Vue.js, so there may be a better way to approach this, but it's done the job I needed to get done.

Upvotes: 1

Related Questions