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.
Related
I have a child Card component:
<template>
<v-card
class="mx-auto"
max-width="500"
color=color
outlined
dark
>
<v-list-item three-line>
<v-list-item-content>
<div class="overline mb-4">
OVERLINE
{{color}}
</div>
<v-list-item-title class="headline mb-1">
Headline 5
</v-list-item-title>
<v-list-item-subtitle>Greyhound divisely hello coldly fonwderfully</v-list-item-subtitle>
</v-list-item-content>
<v-list-item-avatar
tile
size="80"
color="grey"
></v-list-item-avatar>
</v-list-item>
<v-card-actions>
<v-btn
outlined
rounded
text
>
Button
</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
export default {
name: 'Card',
props: {
color: String
}
}
</script>
And from the parent component I want to pass in the color to the child. A part of the parent component's code is shown below.
<template>
<Card v-bind:color="color"/>
</template>
<script>
export default {
data() {
return {
color: "#FFC400"
}
},
}
</script>
As you can see I tried to use a prop to pass the color from the parent to the child, however even though I'm able to pass the data to the child, {{color}} prints out #FFC400 I'm not sure how to assign the color value to the v-card's color attribute. How can I achieve this? Thank you.
The only thing missing is to also bind the prop to the color attribute of the <v-card>, otherwise it's only receiving the string "color", rather than the variable of that name.
You can use v-bind:color="color" or the shorthand :color="color"
<v-card
class="mx-auto"
max-width="500"
:color="color"
outlined
dark
>
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>
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.
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>
I'm using Vuetify for my project and I have a expandable Datatable row that when it clicks, gonna retrieve the data from server side base on ID of the row. However, can't find a right way to implement in the framework so trying to do it itself.
So here I have my datatable and notice that I have a function called getTransactionDetails(), what I did is when user click the row gonna fire this function and pass the transaction_id to work in my server-side.
<v-data-table
v-bind:headers="cashierheaders"
v-bind:items="cashierItems"
v-bind:search="search"
v-bind:pagination.sync="pagination"
:total-items="totalItems"
:loading="loadDatatable"
class="cashierDatatable"
item-key="transaction_id"
expand
>
<template slot="items" slot-scope="props">
<tr #click="props.expanded = !props.expanded" style="cursor:pointer;">
<td>
<v-flex>
<v-chip label small color="green lighten-4" class="ml-0">
{{ props.item.transaction_id}}
</v-chip>
</v-flex>
</td>
<td>
{{props.item.pos_transaction_id}}
</td>
<td>{{props.item.transaction_status}}</td>
<td>{{props.item.business_date}}</td>
<td>{{props.item.sale}}</td>
<td>{{props.item.coupon}}</td>
</tr>
</template>
<template slot="expand" slot-scope="props">
<v-card flat dark>
<v-layout>
<v-flex xs12 sm6 sm6>
</v-flex>
<v-flex xs12 sm6 sm6>
<v-card>
<v-card-title>
<v-chip label small color="red lighten-4">Giveaways</v-chip>
<v-chip label small color="red lighten-4">Modifed</v-chip>
</v-card-title>
<v-divider></v-divider>
<v-card-title>
<!-- start of transaction -->
<v-list two-lines subheader dark>
<v-subheader style="">
</v-subheader>
<template v-for="(item,index) in getTransactionDetails(props.item.transaction_id)">
{{ item }}
</template>
</v-list>
<!-- end of transaction -->
</v-card-title>
</v-card>
</v-flex>
</v-layout>
</v-card>
</template>
</v-data-table>
And here is my method for that, here's the problem the return response.data does not return the value to itself getTransactionDetails when I call. Anyone help me with this. But if its just a normal return like return [{value:'test'}] it passes the value to function
getTransactionDetails:function($trans_id){
const data = {
oc_data : ['giveaways'],
transaction_id: $trans_id.substr(1)
}
this.$store.dispatch('getObservedCat',data)
.then(response=>{
return response.data
})
.catch(error=>{
console.log(error)
})
}
Here is my dispatchiing action from vuex
getObservedCat:({commit},obj)=>{
return new Promise((resolve,reject)=>{
axios({
url:'/prod/api/observredCategories',
method:'post',
config:'JSON',
data: obj
})
.then(response=>{
if(response.status == 200){
resolve(response.data)
}
})
.catch(error=>{
if(error.response){
reject(error.response.data);
}
})
})
}