bootstrap-vue toggle expand table row - vue.js

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>`

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

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.

Related

V-data-table template v-slot syntax

Hello and thank you for reading my question.
I have an array of objects looking like this :
[{
id=1,
products= [a,b,c]
},
{
id=2,
products= [d,e,f]
}]
I want to display data in a v-data-table with two columns (id and products) and products items in a nested v-data-table.
So far I found that i should use template and v-slot but I don't find the right way to do it.
<v-data-table
item-key="id"
items={products}
>
<template v-slot="">
<v-data-table> ... </v-data-table>
</template>
</v-data-table>
Instead of the nested table I get
[object Object],[object Object]
How to use template v-slot in tsx files ?
And more generally, how to 'translate' vuetify js to tsx (documentation) ?
Thanks again
you have made a slot which is correct, but you need to tell vuetify which slot you want to access. To access the default <td> slot of all rows you can simply use v-slot:body="{ items }" and pass it the items, so you can create a view per column. (Available slots are listed here Vuetify doc, if you scroll down. Each component has them)
I have made a codepen that you can check out Codepen. As of translating it to tsx, I can't help you, since I haven't worked with it, but if you grasp the concept of how to do it on the vuetify part, you should be good!

Display one object property value, and show another one on hover

the question I have might be hard to understand, so please help me re-organize the question if you can see the better way to put it in.
So, I am building a registration platform.
(1) First, I receive an array of objects of cases the user can sign time to.
(2) Each object consists of 2 properties, "name", "description".
(3) I store the array in the data, end use it in the element provided by a picker called "vue-multiselect", which basically accepts the array and loops over the objects and displays them.
(4) As you can see, it displays both properties and values, which I am trying to avoid. My question is, is it possible to pass only the "name" value into the picker, and display the description value when hovering the first value?
You can find this use case documentation here: https://vue-multiselect.js.org/#sub-custom-option-template
<multiselect v-model="value"
deselect-label=""
select-label=""
placeholder=""
selected-label=""
:show-pointer="true"
:options="projectCases">
<template slot="option" slot-scope="{ option }">
<strong :title="option.description">{{ option.name }}</strong>
</template>
</multiselect>
ps: I use title attribute to implement display-on-hover functionality. you can use any other tooltip library as well.

How do i add color to an entire Vuetify Data Table row with dynamic headers

Good day.
I have a data-table divided by groups with dynamic headers that change depending on whatever months the user choose to obtain information from, so i want to get information from the months of January until April i'll have 5 columns, one with the name of my classifications and 4 related to the months i am searching for.
every group has a row called total that summarizes the expenses of each group for each month and i want to be able to color this entire row with a color of my choosing. How would i go about that, especially when i have dynamic headers that change whenever the user searches for a time period?
<v-data-table
dense
:headers="headers"
:items="classifications"
item-key="classification"
group-by="classification_group"
disable-sort
hide-default-footer
disable-pagination
class="elevation-1"
>
<template v-slot:group.header="{items, isOpen, toggle}">
<th colspan=1000000>
<v-icon #click="toggle"
>{{ isOpen ? 'mdi-minus' : 'mdi-plus' }}
</v-icon>
{{ items[0].classification_group }}
</th>
</template>
</v-data-table>
One solution is to apply a class to the "total" row's tr element and have CSS that is applied to this class.
So in my v-data-table template, I have a v-if that detects if the tr element is for a "total" row and, if so, applies a table-row-total class.
Then, in that component's <style> section I apply something like:
.my-table-name .v-data-table tr.table-row-total {
background-color: #ffff00 !important;
}
You may want to double-check the Vuetify data tables API, but to the best of my knowledge, I don't know of a more sophisticated way in Vuetify to handle styling 'special case' rows in a datatable -- so, the method above worked fine for me.

Use fallback content of slot only if condition is met

I would like to know if there is a way to do what I'm trying to describe below:
Let's suppose we have a component with a slot, and a fallback content has been defined.
When using this component elsewhere, I would like to have the following behavior:
<TheComponent>
<template v-slot:name="{ data }">
<fallback v-if="condition(data)"/>
</template>
</TheComponent>
I suppose the fallback tag (or similar) does not exists (at least, I didn't find it...). So I suppose I'm thinking the wrong way, but I can't find a solution to my problem.
The thing is that I can't alter the TheComponent as it is provided by an external library, and I don't want to re-create the content.
If it can help, in fact, I'm trying to hide the expand button to prevent to expand a row in a Vuetify data-table, depending on if the row has something to show or not in it's expanded part. So I would like to write something that behave like:
<v-data-table :items="items" show-expand ...>
<template v-slot:item.data-table-expand="{ item }">
<!-- Here I want the default behavior only if my item respects some condition -->
<fallback v-if="condition(item)"/>
<!-- Otherwise, I don't want to display the button that expands the row -->
</template>
</v-data-table>
Thank you in advance for your help.
After quite a lot of "googling" I don't think its possible. IMHO your best bet is to replicate the default slot content Vuetify generates and put it under your own condition (v-if="item.description" in my example):
<v-data-table :headers="headers" :items="people" show-expand>
<template v-slot:expanded-item="{ item, headers }">
<td :colspan="headers.length">{{ item.description }}</td>
</template>
<template v-slot:item.data-table-expand="{ item, isExpanded, expand }">
<v-icon
v-if="item.description"
:class="['v-data-table__expand-icon', { 'v-data-table__expand-icon--active': isExpanded }]"
#click.stop="expand(!isExpanded)"
>$expand</v-icon>
</template>
</v-data-table>
I understand this solution is brittle and can break anytime Vuetify change something but i don't think there is better solution now...
Example

Vue-Tables-2: How to pass a VueJS custom filter?

How would one go about applying a VueJS filter (i.e. {{ price | currency }}) to data displayed using vue-tables-2?
I tried playing around with slots with one of the demo tables to no avail: https://jsfiddle.net/jfa5t4sm/11/
This is a bit annoying, as 'custom filters' mean different things in different context, so searching the docs is not bearing fruit.
Anyone have ideas?
Since it's a scoped slot you have to access the value through the props object and give it the correct slot name.
<template slot="price" scope="props">
<div>
<p>{{ props.row.price | currency }}</p>
</div>
</template>
Working JsFiddle