I am using vuetify 2.3.10. The issue I am facing here is the v-img shows the image_url instead of the image. I tried something like this https://stackoverflow.com/a/53411531/12763413 but it didnt work for me. Please help me find the issue.
<template>
<v-container fluid grid-list-lg>
<v-card flat>
<v-data-table
:headers="headers"
:items="users"
v-model="users"
:sort-by="['full_name']"
class="elevation-1"
>
<template slot="items" slot-scope="props">
<td><v-img class="user-image" :src='props.item.image_url'/></td>
<td class="full-name">{{ props.item.full_name }}</td>
</template>
</v-data-table>
</v-card>
</v-container>
</template>
<script>
export default {
props: ['users'],
data: () => ({
headers: [
{ text: '', value: 'image_url', sortable: false },
{ text: 'Name', value: 'full_name', sortable: false }
]
})
};
</script>
Problem is not in v-img but in your usage of v-data-table - You are using non-existent slot items (should be item) so v-data-table is ignoring your slot content and rendering content of your users data as is...that's why you see url's instead of images
Also you should wrap the content item slot into <tr></tr>
<template>
<v-container fluid grid-list-lg>
<v-card flat>
<v-data-table
:headers="headers"
:items="users"
v-model="users"
:sort-by="['full_name']"
class="elevation-1"
>
<template slot="item" slot-scope="props">
<tr>
<td><v-img class="user-image" :src='props.item.image_url'/></td>
<td class="full-name">{{ props.item.full_name }}</td>
</tr>
</template>
</v-data-table>
</v-card>
</v-container>
</template>
Related
I've made a custom datatable component, where my Table.vue file is shown below:
<template>
<div>
<v-data-table
:headers="headers"
:items="items"
:search="search"
:loading="loading"
loading-text="Loading... Please wait"
dense
>
<template v-slot:top>
<v-toolbar dark flat dense>
<v-toolbar-title>{{ title }}</v-toolbar-title>
<v-spacer></v-spacer>
<v-text-field
v-model="search"
append-icon="mdi-magnify"
label="Search"
single-line
hide-details
></v-text-field>
<v-spacer></v-spacer>
</v-toolbar>
</template>
</v-data-table>
</div>
</template>
<script>
export default {
name: "Table",
props: [
"headers",
"items",
"title",
"itemsPerPage",
"loading",
],
data: function () {
return {
search: '',
}
},
methods: {
},
};
</script>
And I'm using it like that:
<Table
:headers="headers"
:items="groups"
:loading="loading"
title="Baseny"
>
</Table>
Everything is fine, but I want to add custom columns with actions for every input (every input has different ID)
Normally (without a custom component) I'd use the following code:
<v-data-table
:headers="headers"
:items="times"
:items-per-page="5"
:search="search"
:loading="loading"
loading-text="Ładowanie... Proszę czekać"
>
<template v-slot:top>
<v-toolbar dark flat dense>
<v-toolbar-title>Lista zajęć</v-toolbar-title>
<v-spacer></v-spacer>
<v-text-field
v-model="search"
append-icon="mdi-magnify"
label="Szukaj"
single-line
hide-details
></v-text-field>
<v-spacer></v-spacer>
<v-btn
color="primary"
:to="{ name: 'admin.times.create' }"
>
Dodaj zajęcie
</v-btn>
</v-toolbar>
</template>
<template v-slot:item.actions="{ item }">
<v-icon
small
class="mr-2"
#click="show(item)"
>
mdi-pool
</v-icon>
<v-icon
small
class="mr-2"
#click="edit(item)"
>
mdi-pencil
</v-icon>
</template>
</v-data-table>
I'm using this v-slot:
<template v-slot:item.actions="{ item }">
<v-icon
small
class="mr-2"
#click="show(item)"
>
mdi-pool
</v-icon>
<v-icon
small
class="mr-2"
#click="edit(item)"
>
mdi-pencil
</v-icon>
</template>
However, when I wrote the custom reusable table components it didn't work when I put these lines into tag.
How can I use my custom components properly in this scenario?
What you want to achieve is I believe a wrapper component. You want to wrap a component on top of another one to let him have some custom properties that you want to reuse in your application.
What you need is a small snippet that will allow your slots to be used:
<!-- pass through scoped slots -->
<template v-for="(_, scopedSlotName) in $scopedSlots" v-slot:[scopedSlotName]="slotData">
<slot :name="scopedSlotName" v-bind="slotData" />
</template>
<!-- pass through normal slots -->
<template v-for="(_, slotName) in $slots" v-slot:[slotName]>
<slot :name="slotName" />
</template>
You can find the source of this here
Basically, here how you can rewrite your CustomTable.vue:
<template>
<div>
<v-data-table
v-bind="$attrs"
v-on="$listeners"
:search="search"
loading-text="Loading... Please wait"
dense
>
<!-- pass through scoped slots -->
<template
v-for="(_, scopedSlotName) in $scopedSlots"
v-slot:[scopedSlotName]="slotData"
>
<slot :name="scopedSlotName" v-bind="slotData" />
</template>
<!-- pass through normal slots -->
<template v-for="(_, slotName) in $slots" v-slot:[slotName]>
<slot :name="slotName" />
</template>
<template v-slot:top>
<v-toolbar dark flat dense>
<v-toolbar-title>{{ title }}</v-toolbar-title>
<v-spacer></v-spacer>
<v-text-field
v-model="search"
append-icon="mdi-magnify"
label="Search"
single-line
hide-details
></v-text-field>
<v-spacer></v-spacer>
</v-toolbar>
</template>
</v-data-table>
</div>
</template>
<script>
export default {
name: "CustomTable",
props: ["title"],
data: function () {
return {
search: "",
};
},
methods: {},
};
</script>
I made a codesandbox to show you how it works:
https://codesandbox.io/s/vuetify-2-forked-3lp9y?file=/src/components/CustomTable.vue
I also added automatic attribute and listeners bindings on your table, to allow you to use all the features that Vuetify provides.
I'm pretty new to Vue/Vuetify. I'm working on select option for a site I'm working on, and I want to use an icon as the label as opposed to text. I want to do something like the image below, but I'm not sure if it's even possible. Any guidance would be appreciated.
Thanks!
HTML
<div id="app">
<v-app class="container">
<v-select
v-model="select"
:items="permissions"
label="Select"
item-text="name"
>
<template v-slot:item="slotProps" >
<i :class="['mr-2', 'mdi', slotProps.item.flag]"></i>
{{slotProps.item.name}}
</template>
</v-select>
</v-app>
</div>
VUEJS
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: {
select: null,
permissions: [
{
name: "Global",
flag: "mdi-earth"
},
{
name: "Private",
flag: "mdi-lock"
}
],
}
})
you can use vuetify selection slot for v-select and show the icon of the selected item instead of test.
something like this:
<template>
<v-container fluid>
<v-select
v-model="value"
:items="items"
label="Select Item"
multiple
>
<template #selection="{ item }">
<v-icon> {{ getItemIcon(item) }} </v-icon>
</template>
</v-select>
</v-container>
</template>
and you need to write the getItemIcon method as to return the icon based on the text.
For some reason my side it does not work as I wanted - the icon to be inside the selection text and when selected, to show it. Therefore, I added another template as follows:
<template>
<v-container fluid>
<v-select
v-model="value"
:items="items"
label="Select Item"
>
<template v-slot:item="{ item }">
<v-icon> {{ getItemIcon(item) }} </v-icon>
</template>
<template #selection="{ item }">
<v-icon> {{ getItemIcon(item) }} </v-icon>
</template>
</v-select>
</v-container>
</template>
If someone knows easier way to do so, I will be happy to see it, because, currently I have a repeatable code for the .
I'am using vuetify and i want make auto complete like the one on their official site.
But i'm faces some issues :
The items value not appear in the return list and i don't know how to make appear the links.
Here is my code.
Thanks You
<template>
<v-app>
<v-app-bar app color="primary" dark>
<v-app-bar-nav-icon #click="drawer = true"></v-app-bar-nav-icon>
<v-toolbar-title> Board </v-toolbar-title>
<v-spacer></v-spacer>
<v-autocomplete
:loading="loading"
:filter="v => v"
:items="items"
:search-input.sync="search"
v-model="select"
flat hide-no-data hide-details return-object placeholder="Search ...">
<v-list-tile
slot="prepend-item"
class="grey--text">
{{ items.length }} menus found
</v-list-tile>
<template slot="selection" slot-scope="{ item }">
{{item.name}} {{item.url}}
</template>
<template slot="item" slot-scope="{ item }">
<v-list-tile-content>
<p class='fullName'>{{item.name}} {{item.url}}</p>
</v-list-tile-content>
</template>
</v-autocomplete>
</v-app-bar>
<v-main>
<HelloWorld/>
</v-main>
</v-app>
I went through your issue and try to make a codepen and it worked.
My suggestion is that you should consider data structure when you use object with auto complete and it 's needed even you use v-select.
Please check this pen. https://codepen.io/endmaster0809/pen/qBZRywZ
items: [
{
name: 'Alerts',
url: 'https://vuetifyjs.com/en/components/alerts/'
},
{
name: 'Autocompletes',
url: 'https://vuetifyjs.com/en/components/autocompletes/#autocompletes'
}
],
select: {
name: 'Alerts',
url: 'https://vuetifyjs.com/en/components/alerts/'
},
I am facing a very weird situation with Vuetify forms. I have a Vuetify data table that follows the example used in the documentation as well as a dialog box that in fact includes a form. I am using prop to pass data from parent to child and I am following Vue and its best practice which consist of using prop as initial value for data variable. I then use to populate the form. I can edit the form and submit new values without any issue, but I created a cancel button that clears the form. when I do that, it also clears the parent fields that are in my data table. it is like the form reset is propagated from the child to its parent. so with the code hereunder, the {{props.item.order.dueDate}} is cleared when I clear the form of the child.v-bind is not supposed to behave like that.
I lost too many hours trying to find a reason but could not find anything
thanks
here is the code of the data table (parent)
<template>
<v-card>
<v-card-title class="display-3">
{{ tableTitle }}
<v-spacer></v-spacer>
<v-text-field
v-model="search"
append-icon="search"
label="Search"
single-line
hide-details
></v-text-field>
</v-card-title>
<v-data-table
:headers="headers"
:search="search"
:items="orderItems"
item-key="_id"
class="elevation-1"
:expand="expand"
>
<template v-slot:items="props">
<tr #click="props.expanded = !props.expanded">
<td class="px-2">{{ props.item.id }}</td>
<td class="text-xs px-2">{{ props.item.title }}</td>
<td class="text-xs px-2">{{ props.item.order.date | date }}</td>
<td class="text-xs px-2">{{ props.item.order.dueDate | date }}</td>
<td class="text-xs px-2">{{ props.item.count }}</td>
<td v-if="props.item.status" class="text-xs px-2">{{ props.item.status.type }}</td>
<td v-else class="text-xs px-2">New Order</td>
<td v-if="props.item.status" class="text-xs px-2"><span><v-icon color="green darken-2" v-if="props.item.status.signalSent">mail_outline</v-icon><v-icon #click.stop="sendSignal(props.item)" color="red darken-2" v-else>unsubscribe</v-icon> {{ props.item.status.datetime | date}}</span></td>
<td v-else class="text-xs px-2">-</td>
</tr>
</template>
<template v-slot:expand="props">
<v-card flat>
<list-orders-details v-bind:order="props.item"></list-orders-details>
</v-card>
<v-btn
#click.stop="showDialog()"
color="red darken-2"
fixed
dark
small
bottom
right
fab
>
<v-icon>edit</v-icon>
</v-btn>
<v-dialog v-model="editOrder" persistent>
<edit-order-item ref="clearEdit" v-bind:itemChild="props.item"></edit-order-item>
<v-btn class="cancel" dark color="red darken-2" #click="cancelEdit()">cancel</v-btn>
</v-dialog>
</template>
<v-alert slot="no-results" :value="true" color="error" icon="warning">
Your search for "{{ search }}" found no results.
</v-alert>
</v-data-table>
</v-card>
</template>
in the script of the parent:
cancelEdit() {
this.editOrder=false
this.$refs.clearEdit.clear()
}
and an extract of the child :
<template>
<v-form
#submit.prevent
ref="form"
class="white"
>
<v-container>
<h4>Status</h4>
<v-divider class="red darken-2"></v-divider>
<v-layout row wrap align-center justify-start>
<v-flex xs12 sm4 md3>
<v-select
:items="status"
v-model="orderItem.itemStatus.type"
outline
label="Status"
></v-select>
...
export default {
name: 'EditOrderItem',
components: {
},
props: ['itemChild'],
data() {
return {
dialog: false,
order: {
apikey: this.itemChild.order.apikey,
orderId: this.itemChild.order.id,
...
},
},
methods: {
submit () {
const formContent = {
order_id: this.itemChild.order._id,
item_id: this.itemChild._id,
order: this.order,
item: this.orderItem,
}
console.log(formContent)
},
clear () {
this.$refs.form.reset()
}
},
I cant filter my current visible result in my datatable without triggering a new api call. Each time I click on one of the columns the datatable makes a new API call to the very same page, so its not even appending any parameters to the api call like order desc etc.. So how can I filter my result without making a new api call
My code:
<v-card>
<v-card-title>
My data
<v-spacer></v-spacer>
<v-flex xs2>
<v-text-field
append-icon="search"
label="Search data"
single-line
hide-details
v-model="search"
></v-text-field>
</v-flex>
</v-card-title>
<v-data-table
:headers="headers"
:items="items"
:total-items="pagination.totalItems"
:pagination.sync="pagination"
:search="search"
item-key="combo_id"
:rows-per-page-items="[50, 50]"
hide-actions
>
<template slot="items" slot-scope="props">
<tr #click="getCombo(props.item.combo_id); props.expanded = !props.expanded">
<td class="text-xs-left">{{ props.item.data }}</td>
<td class="text-xs-left">{{ props.item.data2 }}</td>
<td class="text-xs-left">{{ props.item.data3 }}</td>
<td class="text-xs-left">{{ props.item.data4 }}</td>
<td class="text-xs-left">{{ props.item.data5 }}</td>
<td class="text-xs-left">{{ props.item.data6 }}</td>
<td class="text-xs-left">{{ props.item.data7 }}</td>
</tr>
</template>
<template slot="expand" slot-scope="props">
<v-card flat>
<v-card-text>
<v-btn color="primary" dark #click.stop="commentDialog = true">Show comments</v-btn> Tags: <strong>{{ comboItemTags }}</strong>
<v-btn color="warning" class="right" #click.stop="editDialog = true">Edit system</v-btn>
</v-card-text>
</v-card>
</template>
</v-data-table>
<div class="text-xs-center pt-2">
<v-pagination v-model="pagination.page" :length="pages" :total-visible="10"></v-pagination>
</div>
</v-card>
data () {
return {
search: '',
items: [],
pagination: {
page: 1,
rowsPerPage: 50,
totalItems: 0
},
...
...
},
watch: {
pagination: {
handler() {
this.getAllSystemsNewPage(this.pagination.page); //Fetch new data and push into items
},
deep: true
}
},
If you're fetching data from a server and watching the pagination object, it's assumed that all processing (pagination, sorting, searching) happens server-side.
See this example. Everything that happens inside the promise in getDataFromApi is a simulation of what happens on the server. You will need to pass along the relevant data from the pagination object as parameters to your server API call and return the correct items.
edit:
How you pass along the pagination data to your backend is outside of vuetify's scope and depends on what the backend looks like. But a simple example is something like this:
getDataFromApi () {
const { sortBy, descending, page, rowsPerPage } = this.pagination
const query = `page=${page}&sort_by=${sortBy}&sort_order=${descending ? 'desc' : 'asc'}&rows_per_page=${rowsPerPage}`
axios.get(`/api/endpoint?${query}`).then(...)
}