vuetify v-autocomplete table dropdown - javascript

Trying to create a v-autocomplete dropdown with a table format. For example I have a select with a list of products each one with product name, keywords, prefix etc... want to be able to display this info as table on a dropdown.
I was able to get the header working but then when I use a template for the items using
<v-autocomplete
dense
label="Select product"
:items="products"
:item-value="product_name"
:filter="customFilter"
:return-object="true"
v-model="form.product">
<template slot="selection" slot-scope="{ item, selected }">
{{ item.product_name ? item.product_name : ""}}
</template>
<template v-slot:prepend-item>
<v-simple-table dense>
<thead>
<tr>
<th>Full Name</th><th>Short Name</th><th>Prefix</th><th>Keywords</th>
</tr>
</thead>
</v-simple-table>
</template>
<template slot="item" slot-scope="{item}">
<v-simple-table>
<tbody>
<tr>
<td>{{ item.product_name }} </td><td>{{ item.product }}</td><td>{{ item.view_prefix }}</td><td>{{ item.keywords }}</td>
</tr>
</tbody>
</v-simple-table>
</template>
</v-autocomplete>
So this shows a perfect header but the data inside doesn't line up. The filter works fine and I can search for items on each column fine. Just want to be able to line up the header with the data properly. Let me know if anyone can help!

Related

Clicking on row in v-data-table with template rows

When I added template rows (so that they have special formatting based on condition):
<v-data-table
:headers="headers"
:items="desserts"
:items-per-page="5"
class="elevation-1"
#click:row="clickedHandle"
>
<template v-slot:item="props">
<tr v-if="props.item.name.includes('Fro')">
<td>{{ props.item.name }}</td>
<td v-for="itemx in myheaders">{{ toThousands(props.item[itemx]) }}</td>
</tr>
<tr v-else>
<td v-for="itemx in props.item">{{ itemx }}</td>
</tr>
</template>
</v-data-table>
The function that is supposed to be called on row click clickedHandle does not fire up at all. Why is that so?
Here is the example where you can check this behaviour:
https://codesandbox.io/s/vuetify-playground-forked-lro4w?file=/src/layout.vue
The table does not seem to react on row click at all.
clickedHandle(value) {
console.log(value);
},
clickedHandle should log some value on row click.
Customize each cell individually as they do in the v-data-table row customization docs, not the whole row. You can use a v-for to dynamically target the cell slots you want (in conjunction with your myheaders array):
<template v-for="header in myheaders" v-slot:[`item.${header}`]="props">
<template v-if="props.item.name.includes('Fro')">
{{ toThousands(props.item[header]) }}
</template>
<template v-else>
{{ props.item[header] }}
</template>
</template>
You could avoid this slot and filter complexity by preparing your data ahead of time in a computed.
Here is an updated CodeSandbox
try with this code:
<v-data-table
:headers="headers"
:items="desserts"
hide-actions
class="elevation-1"
>
<template slot="items" slot-scope="myprops">
<tr v-if="myprops.item.name.includes('Fro')">
...
</tr>
<tr v-else>
<td v-for="itemx in props.item">{{ itemx }}</td>
</tr>
</template>
</v-data-table>

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.

Vue - button is not visible inside v-data-table

I have a problem with v-data-table. I want to add button for edit, delete and add new product to my v-data-table. Data comes from my rest api and is assign via my getter CARS to v-data-table. Everything is fine and every single row is displayed but button is not shown.... I tried a lot of different approaches but it still doesn't work..
I would be grateful if You help me.
Best regards!
Here is my code.
<v-data-table
v-model="selected"
:headers="headers"
:items=CARS
:single-select="singleSelect"
item-key="id"
show-select class="elevation-1"
>
<template slot="items" slot-scope="props">
<td>{{ props.item.id }}</td>
<td>{{ props.item.vin }}</td>
<td>{{ props.item.register_number}}</td>
<td>{{ props.item.cost}}</td>
<td>{{ props.item.latitude }}</td>
<td>{{ props.item.longitude}}</td>
<td>{{ props.item.service}}</td>
<td>{{ props.item.reservation}}</td>
<td class="justify-content-left layout">
<v-btn icon #click.prevent="editUser(props.item)">
<v-icon color="blue">edit</v-icon>
</v-btn>
</td>
</template>
</v-data-table>

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.

How to make content in an expand slot of a data table in VuetifyJS searchable?

I'm using the VuetifyJS/VueJS data table with an expand slot. How to make the content in the expand slot searchable? I tried wrap the content within <td></td> but that didn't work.
Here is a codepen example: https://codepen.io/anon/pen/VBemRK?&editors=101
If you search for "find me" it always results in a Your search for "find me" found no results.
<v-data-table
:headers="headers"
:items="desserts"
:search="search"
item-key="name"
>
<template slot="items" slot-scope="props">
<tr #click="props.expanded = !props.expanded">
<td>{{ props.item.name }}</td>
<td class="text-xs-right">{{ props.item.calories }}</td>
<td class="text-xs-right">{{ props.item.fat }}</td>
<td class="text-xs-right">{{ props.item.carbs }}</td>
<td class="text-xs-right">{{ props.item.protein }}</td>
<td class="text-xs-right">{{ props.item.iron }}</td>
</template>
<template slot="expand" slot-scope="props">
<v-card flat>
<v-card-text><td>Peek-a-boo! Please find me too.</td></v-card-text>
</v-card>
</template>
<v-alert slot="no-results" :value="true" color="error" icon="warning">
Your search for "{{ search }}" found no results.
</v-alert>
</v-data-table>
Use a custom filter.
First, create a custom filter method:
methods: {
customFilter(items, search) {
return items.filter(dessert => JSON.stringify(dessert).toLowerCase().indexOf(search.toLowerCase()) !== -1)
}
}
then add :custom-filter="customFilter" to the v-data-table:
<v-data-table
:headers="headers"
:custom-filter="customFilter"
:items="desserts"
:search="search"
item-key="name"
>
See this updated codepen:
https://codepen.io/WisdomSky/pen/PBNvYY
Since Vuetify version >= 2 you'll need to use the custom-filter prop which has a new pattern.
export default {
methods: {
customDataTableItemsFilter(value, search, items) {
/*
Filter for individual words in search string. Filters
all object values rather than just the keys included
in the data table headers.
*/
const wordArray = search
.toString()
.toLowerCase()
.split(' ')
.filter(x => x)
return wordArray.every(word =>
JSON.stringify(Object.values(items))
.toString()
.toLowerCase()
.includes(word)
)
}
}
}

Categories

Resources