expand slot on data table not working inside wrapper component
I have a wrapper component around v-data-table like so:
<template>
<div>
<wrapper-data-table
:headers="tableHeaders"
:items="partLines"
:expand="expand"
>
<template v-slot:items="line">
<tr #click="line.expanded = !line.expanded">
<td>{{ line.item.binLocation }}</td>
<td>{{ line.item.reqQuantity }}</td>
</tr>
</template>
<template v-slot:expand="line">
<v-card flat>
<v-card-text>Peek-a-boo!</v-card-text>
</v-card>
</template>
</wrapper-data-table>
</div>
</template>
Wrapper Data-Table component
<template>
<div>
<div>
<v-data-table
v-model="selected"
v-bind.sync="tableProps"
:expand="expand"
item-key="name"
>
<!-- Pass on all slots -->
<slot v-for="slot in Object.keys($slots)" :name="slot" :slot="slot" />
<!-- Pass on all scoped slots -->
<template v-for="slot in Object.keys($scopedSlots)" :slot="slot" slot-scope="scope">
<slot :name="slot" v-bind="scope" />
</template>
</v-data-table>
</div>
</div>
</template>
I'm passing through all scoped slots which mostly works fine. However the expand slot doesn't seem to work. I want to expand the row on row click just like the example in the docs.
It works if I'm using the data table directly without the wrapper. however, when it's wrapped, there is no expansion. I can see that the 'expanded' prop is being changed though.
Related
I have a table component, and this table component has the ability to select attributes, however I only want this ability to be available when I need it to be, aka not every time it's rendered. How do I do this?
Functionality snippet from Component.vue to only be active when in a certain file ie Component2.vue
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<b-table-column field="columnValue" v-slot="props2" class="attr-column">
<b-table :bordered="false" class="attr-table" :striped="true" :data="props2.row.columnValues">
<b-table-column field="columnName" v-slot="itemProps">
<SelectableAttribute :attr-name="props2.row.fieldClass" :attr-id="itemProps.row.id" :model-id="itemProps.row.id" model-name="NewParticipant">
{{ itemProps.row.value }}
</SelectableAttribute>
</b-table-column>
</b-table>
</b-table-column>
</b-table>
Component.vue
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<template>
<b-table :striped="striped" :bordered="false" :data="participants" detailed class="participant-table" :row-class="() => 'participant-row'">
<b-table-column field="primaryAlias" :label="t('participant.table.primary_alias')" v-slot="props">
<template v-if="props.row.primaryAlias">
<SelectableAttribute attr-name="Alias" :attr-id="props.row.primaryAlias.id" :model-id="props.row.id" model-name="NewParticipant">
{{ props.row.primaryAlias.value }}
</SelectableAttribute>
</template>
<template v-else>-</template>
</b-table-column>
<b-table-column field="primaryEmail" :label="t('participant.table.primary_email')" v-slot="props">
<template v-if="props.row.primaryEmail">
<SelectableAttribute attr-name="Email" :attr-id="props.row.primaryEmail.id" :model-id="props.row.id" model-name="NewParticipant">
{{ props.row.primaryEmail.value }}
</SelectableAttribute>
</template>
<template v-else>-</template>
</b-table-column>
<b-table-column field="primaryAddress" :label="t('participant.table.primary_address')" v-slot="props">
<template v-if="props.row.primaryAddress">
<SelectableAttribute attr-name="Address" :attr-id="props.row.primaryAddress.id" :model-id="props.row.id" model-name="NewParticipant">
{{ props.row.primaryAddress.value }}
</SelectableAttribute>
</template>
<template v-else>-</template>
</b-table-column>
*<b-table-column field="primaryPhone" :label="t('participant.table.primary_phone')" v-slot="props">
<template v-if="props.row.primaryPhone">
<SelectableAttribute attr-name="Phone" :attr-id="props.row.primaryPhone.id" :model-id="props.row.id" model-name="NewParticipant">
{{ props.row.primaryPhone.value }}
</SelectableAttribute>
</template>
<template v-else>-</template>
</b-table-column>*
<b-table-column v-slot="props" cell-class="cell-action">
<slot v-bind="props.row">
</slot>
</b-table-column>
<template slot="detail" slot-scope="props">
<b-table class="attrs-detail-container" :data="tableDataToDataValueCells(props.row)" cell-class="with-bottom-border">
<b-table-column field="columnName" v-slot="props">
<b>{{ props.row.columnName }}</b>
</b-table-column>
<b-table-column field="columnValue" v-slot="props2" class="attr-column">
<b-table :bordered="false" class="attr-table" :striped="true" :data="props2.row.columnValues">
<b-table-column field="columnName" v-slot="itemProps">
<SelectableAttribute
:attr-name="props2.row.fieldClass"
:attr-id="itemProps.row.id"
:model-id="itemProps.row.id"
model-name="NewParticipant"
>
{{ itemProps.row.value }}
</SelectableAttribute>
</b-table-column>
</b-table>
</b-table-column>
</b-table>
</template>
</b-table>
</template>
You can achieve this by using props that you pass while calling that component. That prop could be anything you need. Here is a small example with simple true/false prop:
// Set the prop in your called component, in this case a boolean
props: {
myBoolean: Boolean
}
// Passing the prop from your parent to the component, where it has to be a property, in this case called myBooleanFromParent
<my-component :myBoolean="myBooleanFromParent"></my-component>
// In your component your template changes according to the passed prop from your parent
<template>
<div>
<div v-if="myBoolean">
If myBoolean is true
</div>
<div v-else>
Else, so if myBoolean is false
</div>
</div>
</template>
This is, as stated, a small and simple example. You can pass any kind of data with props. It could also be a object full of data to handle multiple conditions.
I have v-data-table as its own component to make it more generic for my components. I would like to have the option to provide that component how each item in the table is formatted. That would be done with a slot. But the problem is, that the provided slot has a slot for v-data-table. See the example, this is difficult to explain.
In my DataTable component I have:
<v-data-table
:headers="tableHeaders"
:items="items"
:item-key="itemKey"
:loading="isLoading"
v-model="selectedRows"
show-select
>
<!-- What do i put here? -->
</v-data-table>
And I use that data table from my other component like this:
<data-table
:table-headers="tableHeaders"
:items="messages"
:is-loading="isLoading"
:selected-rows="selectedRows"
:item-key="'MessageID'"
>
<template v-slot:item.actions="{ item }">
<v-btn :to="`messages/${item.MessageID}`" icon>
<v-icon>mdi-chevron-right</v-icon>
</v-btn>
</template>
<template v-slot:item.CreatedDateTime="{ item }">
<span>{{ format(new Date(item.CreatedDateTime)) }}</span>
</template>
</data-table>
I need the result to be rendered as:
<v-data-table
:headers="tableHeaders"
:items="items"
:item-key="itemKey"
:loading="isLoading"
v-model="selectedRows"
show-select
>
<template v-slot:item.actions="{ item }">
<v-btn :to="`messages/${item.MessageID}`" icon>
<v-icon>mdi-chevron-right</v-icon>
</v-btn>
</template>
<template v-slot:item.CreatedDateTime="{ item }">
<span>{{ format(new Date(item.CreatedDateTime)) }}</span>
</template>
</v-data-table>
So the problem is, how do I provide the templates within data-table tag to be rendered within v-data-table tag?
I had the exact same issue. I found a solution utilizing the $scopedSlotes object, like this:
<v-data-table
:headers="tableHeaders"
:items="items"
:item-key="itemKey"
:loading="isLoading"
v-model="selectedRows"
show-select
>
<template
v-for="slot in Object.keys($scopedSlots)"
:slot="slot"
slot-scope="scope"
>
<slot
:name="slot"
v-bind="scope"
></slot>
</template>
</v-data-table>
You will have to re-expose the slots in your "wrapper" component:
<v-data-table
:headers="tableHeaders"
:items="items"
:item-key="itemKey"
:loading="isLoading"
v-model="selectedRows"
show-select
>
<template v-slot:body="bodyParams">
<slot name="body" v-bind="bodyParams" />
</template>
<template v-slot:expanded-item="expandedParams">
<slot name="expanded-item" v-bind="expandedParams" />
</template>
<template v-slot:header="headerParams">
<slot name="header" v-bind="headerParams" />
</template>
<template v-slot:footer="footerParams">
<slot name="footer" v-bind="footerParams" />
</template>
<template v-slot:item="itemParams">
<slot name="item" v-bind="itemParams" />
</template>
<template v-slot:progress="progressParams">
<slot name="progress" v-bind="progressParams" />
</template>
<!-- put here the other slots you are interested in -->
</v-data-table>
I am trying to add a v-chip-group in a v-select v-slot=selection but am failing.
Due to design requirements, I have to persist some placeholder text in a multi-select but only have so much width for the component. I want the chips to overflow to the right with a scroll interface like the default v-chip-group but can't seem to work it together.
Goal
Current
How can I get the proxy BaseSelect component, which is basically a wrapper for default styling of a v-select, to work as v-chip-group? I also want the chips to work with the deletable-chips prop.
Component
<BaseSelect
multiple
class="flex-0-1-30rem"
localKey="breakdownBy"
:items="localizedBreakdownList"
:value="breakdowns"
:placeholder="$t('select-breakdownBy-label')"
#change="setBreakdowns"
>
<template v-slot:selection="{ item, select, index }">
<span
v-if="index === 0"
class="text--uppercase"
>{{ $t('select-breakdownBy-label') }}</span>
<v-chip color="primary" class="text--white">{{ item.text }}</v-chip>
</template>
</BaseSelect>
BaseSelect component
<template>
<v-select
hide-details
solo
dense
:append-icon="mdiMenuDown"
:items="items"
v-bind="$attrs"
v-on="$listeners"
>
<!-- Passes scopedSlots to child -->
<template v-for="(_, slot) of $scopedSlots" v-slot:[slot]="scope">
<slot :name="slot" v-bind="scope" />
</template>
<!-- Default scopedSlots -->
<template v-if="!hasScopedSlot('selection')" v-slot:selection="{ item }">
<span
:class="slotClasses"
>{{ item.text || $t(`select-${localKey}-option-${item.value || item}`) || item }}</span>
</template>
<template v-if="!hasScopedSlot('item')" v-slot:item="{ item }">
<span
:class="slotClasses"
>{{ item.text || $t(`select-${localKey}-option-${item.value || item}`) || item }}</span>
</template>
</v-select>
</template>
I'm using last version of vuetify and trying to figure out how to make slots work. Documentation about select may be find here
VSelectWithValidation
<v-select v-model="innerValue" :error-messages="errors" v-bind="$attrs" v-on="$listeners">
<template slot="selection" slot-scope="data">
{{ data.item.name }}
</template>
<template slot="item" slot-scope="data">
{{ data.item.name }} - {{ data.item.description }}
</template>
</v-select>
TestComponent
<VSelectWithValidation
rules="required"
:items="items"
v-model="select"
label="Select">
// I WOULD LIKE SLOTS TO BE AT THIS LEVEL
</VSelectWithValidation>
Basically, I would like the slots to be customized so I need to move them out of the VSelectWithValidation component to be set on the TestComponent
I tried different variations with no success.
https://codesandbox.io/s/veevalidate-components-vuetify-u11fd
VSelectWithValidation
You need to create slot inside your template slot item and bind scope data to able to use from other component ..
<template slot="item" slot-scope="data">
<slot name="item" v-bind="data"></slot>
</template>
TestComponent
You can access that slot by writing v-slot:YourSlotName="hereIsBindData"
<template v-slot:item="data">
{{ data.item.name }} // you can code here whatever you like
</template>
I am trying to create a wrapper component around an existing component (q-table from the quasar-framework).
<!-- MyTable.vue -->
<template>
<q-table :title="title" ...>
<template v-slot:top="props">
...
</template>
<template v-slot:body="props">
<q-tr :props="props">
...
</q-tr>
</template>
</q-table>
</template>
<template v-slot:body="props"> and <template v-slot:top="props"> are slots of the q-table component.
How to overwrite these slots in the App.vue:
<!-- App.vue -->
<template>
<div>
<my-table>
???
</my-table>
</div>
</template>