How can I expand slots in v-data-table component in Vuetify? - javascript

Hello I am trying expand default v-data-table component from Vuetify to avoid code redundancy. I have few components with v-data-table. It works on the same principles but table headers can be different. I am using v-slots but how I can expand dynamic slots from Vuetify?
When I have to add custom html to one of column (eg. action) in table I am using:
<v-data-table
:headers="questionTableHeaders"
:items="questions.fetchedData"
class="elevation-1"
hide-default-footer
:page.sync="questions.pagination.page"
:items-per-page="questions.pagination.itemsPerPage"
:loading="loadingData"
loading-text="Loading..."
no-data-text="No data.">
<template v-slot:item.action="{ item }">
<v-icon
small
class="mr-2"
title="title"
#click="clickOnTheItem(item)">
fas fa-plus
</v-icon>
</template>
</v-data-table>
But sometime tables don't have column action. How I can prepare dynamic slots in my component dataTable expanded default v-data-table component to make sure that each of the headers passing to my component have a slot that I can use in parent component?
If I have headers:
[
{text: "text1", value: "name"},
{text: "text2", value: "hash"}
]
I can have access to slots item.name and item.hash?
<dataTable :url="examApiUrl" :headers="examTableHeaders">
<template v-slot:item.name="{ item }"></template>
<template v-slot:item.hash="{ item }"></template>
</dataTable>
But as I wrote before, headers can be different. How I can prepare slots in my dataTable component?

Try it
<v-data-table
:headers="questionTableHeaders"
:items="questions.fetchedData"
class="elevation-1"
hide-default-footer
:page.sync="questions.pagination.page"
:items-per-page="questions.pagination.itemsPerPage"
:loading="loadingData"
loading-text="Loading..."
no-data-text="No data.">
<template v-slot:item.action="{ item }">
<v-icon
small
class="mr-2"
title="title"
#click="clickOnTheItem(item)">
fas fa-plus
</v-icon>
</template>
<template v-for="(slot, name) in $scopedSlots" v-slot:[name]="item">
<slot :name="name" v-bind="item"></slot>
</template>
</v-data-table>

Related

How to apply a hover function to a Vue / Vuetify Autocomplete autocomplete list?

I am more of a Vue-Noob, and find it to be a bit complicated to understand. Maybe you fellas see that code, and have the "best practice" or most compact solution for my problem:
I have an autocomplete dropdown box. On expand, i see a list with clickable entries. I would need to get the information of the hovered item, if the mouse hovers over the list.
Like, the method "doFunnyStuff" would push the data of the hovered object on hovering to a method, and do something with it (maybe externally or so)
Thank you in advance for any helpful comment!
<template>
<v-autocomplete
v-model="selected"
dense
outlined
hide-details
return-object
background-color="white"
light
:placeholder="placeholder"
hide-no-data
style="width: 500px"
:loading="loading"
:search-input.sync="query"
:items="items"
clearable
>
<template slot="selection" slot-scope="{ item }" return-object>
<v-list-item #mouseenter="doFunnyStuff(item)">
<v-list-item-content>
<v-list-item-title> {{ item.text }}} </v-list-item-title>
</v-list-item-content>
</v-list-item>
</template></v-autocomplete
>
</template>
</template>
Maybe I misunderstood your question, but when you want to do something with hovered item of expanded list, you should use item slot instead of selection.
Selection slot is used just for your selected item on top of the component, so your code works, but only when you hover your already selected item.
Mouseenter event is not related for any component in vuetify, it's an JS event that may be appended to any component (if was not appended before by vuetify or any different library, ofc).
So your code may be like:
<div id="app">
<v-app id="inspire">
<v-autocomplete
v-model="value"
:items="items"
dense
filled
label="Filled"
>
<template #item="{ item, on, attrs }">
<v-list-item #mouseenter="doFunnyStuff(item)" v-on="on" v-bind="attrs">
<v-list-item-content>
<v-list-item-title> {{ item }} </v-list-item-title>
</v-list-item-content>
</v-list-item>
</template>
</v-autocomplete>
<div>
<p>{{ hoveredItem }}</p>
</div>
</v-app>
</div>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
items: ['foo', 'bar', 'fizz', 'buzz'],
value: null,
hoveredItem: "not hovered yet"
}),
methods: {
doFunnyStuff (item) {
this.hoveredItem = item;
}
}
})
Codepen link with an example

How to custom all headers in v-data-table?

I'm trying to customize all headers in my v-data-table like this
<v-data-table
:headers="headers"
:items="desserts"
:disable-sort="true"
:hide-default-footer="true"
>
<template v-slot:header="{ header }">
{{ header.text.toUpperCase() }}
</template>
</v-data-table>
I saw in the documentation how to do this for only ONE header like this :
<v-data-table
:headers="headers"
:items="desserts"
:disable-sort="true"
:hide-default-footer="true"
>
<template v-slot:header.name="{ header }">
{{ header.text.toUpperCase() }}
</template>
</v-data-table>
but I want to custom ALL headers and I'm not figuring out how to do this. Also my headers are dynamics.
You can do it using the header (not header.<name>) slot. Note that this slot is used for generating all header columns at once. It means that you'll need to dynamically create the <th> tags using a v-for directive.
Also, it is located under the default headers, so you'll need to add the hide-default-header prop.
<v-data-table :headers="headers" :items="desserts" hide-default-header>
<template v-slot:header="{ props }">
<thead>
<tr>
<th v-for="header in props.headers" :key="header.text">
{{ header.text.toUpperCase() }}
</th>
</tr>
</thead>
</template>
</v-data-table>
See this working example.

BootstrapVue access b-table row data in slot template

I have a delete button on each row and I need to get log_id from items to pass to function deleteLog. That function always alerts log_id is undefined.
How can I pass log_id to the function deleteLog without undefined?
<template>
<b-table striped hover :items="items" :fields="fields">
<template v-slot:cell(Delete)>
<b-button variant="danger" v-on:click="deleteLog(log_id)">Delete</b-button>
</template>
</b-table>
</template>
<script>
export default {
data() {
return {
fields: ['Year', 'Month', 'Round', 'Name', 'Delete', 'log_id'],
items: []
}
}
}
</script>
You can access the row data and its log_id through the slot data:
<b-table striped hover :items="items" :fields="fields">
<template v-slot:cell(Delete)="data"> <!-- `data` -->
<b-button variant="danger" v-on:click="deleteLog(data.item.log_id)">Delete</b-button>
</template>
</b-table>
Here's another syntax, destructuring the slot data:
<b-table striped hover :items="items" :fields="fields">
<template v-slot:cell(Delete)="{ item }"> <!-- `item` -->
<b-button variant="danger" v-on:click="deleteLog(item.log_id)">Delete</b-button>
</template>
</b-table>

Vue.js pass slot to wrapped Bootstrap-Vue Table component

I'm trying to create a wrapper for the bootstrap-vue Table component. This component uses slots to define cell templates, like that:
<b-table :items="itemsProvider" v-bind="options">
<template v-slot:cell(id)="data">
///...here goes the template for the cell's of itens key "id"
</template>
</b-table>
So, the wrapper i'm creating is like this:
<div>
<b-table :items="itemsProvider" v-bind="options" >
<slot></slot>
</b-table>
<b-pagination
v-model="currentPage"
:total-rows="rows"
:per-page="perPage"
/>
</div>
And i want to call this component like this:
<TableAjax :options="options">
<template v-slot:cell(id)="data">
///...here goes the template for the cell's of itens key "id"
</template>
</TableAjax>
But, since the slots needed on the b-table component are named, i'm having a hard time passing it from the wrapper.
How can i do that?
Passing slots to a child component can be done like this:
<template>
<div>
<b-table :items="itemsProvider" v-bind="options" >
<template v-slot:cell(id)="data">
<slot name="cell(id)" v-bind="data"></slot>
</template>
</b-table>
<b-pagination
v-model="currentPage"
:total-rows="rows"
:per-page="perPage"
/>
</div>
</template>
But since you may not know the slot names ahead of time, you would need to do something similar to the following:
<template>
<div>
<b-table :items="itemsProvider" v-bind="options" >
<template v-for="slotName in Object.keys($scopedSlots)" v-slot:[slotName]="slotScope">
<slot :name="slotName" v-bind="slotScope"></slot>
</template>
</b-table>
<b-pagination
v-model="currentPage"
:total-rows="rows"
:per-page="perPage"
/>
</div>
</template>

Defining default emit events in a Vue JS component template

I havetwo nested Vue JS components. The child component emits a few events to the parent function which I define inside the parent component declaration. However these same few events are being called every time I am going to be using the component, so I want to be able to omit having to declare them within the props of the parent component. However I am unsure as to where to move the event declarations in the parent component props.
<admin-data-table
:dataTable="dataTable"
:modelName="modelName"
:collection="collection"
:tblShowFields="tblShowFields"
:selectedList.sync="selected"
#change-sort="changeSort"
#edit-row="edit"
#remove-row="remove"
></admin-data-table>
The #change-sort, #edit-row, and #remove-row events will always be defined this way every time I use admin-data-table component, so I want to be able to omit having to declare them.
I tried moving them into the template tag of the child component [admin-data-table], which did not work.
admin-data.table component:
<template
#change-sort="changeSort"
#edit-row="edit"
#remove-row="remove">
<v-flex xs12>
<v-progress-linear :indeterminate="true" :height="3" color="#c79121" :active="dataTable.loadingVal" class="mb-0 mt-5"></v-progress-linear>
<v-data-table :ref="modelName + 'Table'" :value="selectedList" #input="$emit('update:selectedList', $event)" :headers="dataTable.headers" :items="collection" :pagination.sync="dataTable.pagination" select-all item-key="id" class="elevation-1" >
<template v-slot:headers="props">
<tr>
<th><v-checkbox :input-value="props.all" color="#c79121" :indeterminate="props.indeterminate" primary hide-details #click.stop="toggleAllSelected"></v-checkbox></th>
<th v-for="header in props.headers" :key="header.text"
:class="['column sortable', dataTable.pagination.descending ? 'desc' : 'asc', header.value === dataTable.pagination.sortBy ? 'active' : '']"
#click="$emit('change-sort', header.value)">
<v-icon small>arrow_upward</v-icon>
{{ header.text }}
</th>
</tr>
</template>
<template v-slot:items="props">
<tr :active="props.selected">
<td class="text-center align-middle" #click="props.selected = !props.selected">
<v-checkbox :input-value="props.selected" primary hide-details color="#c79121"></v-checkbox>
</td>
<td v-for="(field, key) in props.item" v-if="tblShowFields.includes(key)">{{ field }}</td>
<td class="text-right align-middle">
<v-btn
v-for="(btn, i) in dataTable.rowButtons" :key="i"
:title="btn.title"
:color="btn.color" fab small
#click="btn.click">
<v-icon>{{ btn.icon }}</v-icon></v-btn>
<v-btn title="Edit" color="primary" fab small #click="$emit('edit-row', props.item.id)"><v-icon>edit</v-icon></v-btn>
<v-btn title="Delete" color="error" fab small class="text-white" #click="$emit('remove-row', props.item.id)"><v-icon>delete_outline</v-icon></v-btn>
</td>
</tr>
</template>
<template slot="no-data">
<p class="text-xs-center">No Data</p>
</template>
</v-data-table>
</v-flex>
</template>
<script>
export default {
name: "admin-data-table",
props: [
'dataTable',
'collection',
'modelName',
'collection',
'selectedList',
'tblShowFields'
]
}
</script>
Where can I map these into the admin-data-table component itself as defaults?
I hope I am understanding this correctly. You can set property defaults in vue if you specify the properties as objects instead of an Array.
props:{
'edit-row':{
type:Function,
default: (itemID) => { //function logic}
}
}
VueJS Prop Validation
If you look under the object example they show actually how an object needs to return a function as a default prop. You can then overwrite these props with another outside function if you include one.

Categories

Resources