I found the miss function on vuetify datatable.
I think that my configuration is correct.
This is my datatable vuetify
<v-text-field v-model="search" append-icon="mdi-magnify" label="Search" single-line
hide-details></v-text-field>
</v-card-title>
<v-data-table loading loading-text="Loading... Please wait" :headers="headers"
:items="goodsData" :search="search" :items-per-page="10" class="elevation-1">
<template v-slot:item.typeOfGoods="{ item }">
<div class="userDatatable-inline-title my-3">
<a href="#" class="text-dark fw-500">
<h6 v-if="item.typeOfGoods == 1">Document
#{{item.receiptNumber}}</h6>
<h6 v-if="item.typeOfGoods == 2">Packet
#{{item.receiptNumber}}</h6>
</a>
<p class="pt-1 d-block mb-0">
<i class="fas fa-dolly"></i> via {{item.courier}} • Received at
{{item.created_at}}
</p>
</div>
</template>
<template v-slot:item.receiver="{ item }">
<img class="rounded-circle wh-34"
:src="`/dashboard/img/author/profile/`+item.receiver.avatar"
alt="author">
{{item.receiver.name}}
</template>
<template v-slot:item.status="{ item }">
<span class="media-badge color-white bg-primary" v-if="item.status==0">Available
at
receiptionist</span>
<span class="media-badge color-white bg-success" v-if="item.status==1">Well
received</span>
<span class="media-badge color-white bg-danger"
v-if="item.status==2">Terminated</span>
</template>
<template v-slot:item.actions="{item}">
<a href="#" v-on:click="receivedAction(item.id)" v-if="item.status==0"><span
style="color:blue;"><i class="far fa-check-circle"></i> Update
status</span></a>
<a v-if="item.status==1"><span style="color:green;"><i
class="fas fa-check-circle"></i>
Done</span></a>
</template>
</v-data-table>
This is my script data
// datatable
search: '',
goodsData: [],
headers: [{
text: 'Goods Type',
value: 'typeOfGoods'
}, {
text: 'Recipient',
value: 'receiver'
}, {
text: 'Status',
value: 'status'
}, {
text: 'Actions',
value: 'actions',
filterable: false,
sortable: false
}],
I already read the documentation on codepen and on https://vuetifyjs.com/en/components/data-tables/#api
Or you can see my repo,
https://github.com/bintangjtobing/boxity-app/blob/master/resources/js/components/goodsReceipt.vue
You can see my gif below
Thank you, everyone, hope you can help to solve this prob.
Thank you thank you.
The search only looks in fields you’ve defined. The text “Document” is not in a field, it’s in your template. The number comes from receiptNumber which is not defined in headers or anywhere, it’s just in the template. Therefore the search can’t know about that either.
You’ll need to provide your own filter function as the documentation you linked to explains in the beginning. I don’t see such defined here.
I found a simple solution for this by creating same header and value but hidden for the column used in template.
You can try this:
{ text: "", value: "header_value", align: ' d-none' },
{ text: "Header Name", value: "header_value" }
Wherein you have to hide the other one by using ' d-none' that will be use to still search the value of that column while the other one is use to display the value. Else if you don't want to use this, you can use the other solution stated here, by creating a custom filter/search.
Related
I'm writing a Vue.js app using BootstrapVue. I'm dynamically generating a form based on a simple "field" data structure (see code and screenshot below). The label for each <b-form-group> comes from a label attribute in my field object. It worked fine until I needed a subscript in the label. I'm using the <sub> HTML tag, but v-bind-ing the label treats the HTML as plain text. See the first column of inputs:
Next I tried using <b-form-group>'s label slot instead, using mustache templates. As documented, this also interprets the value as plain text, so I get the same result -- see the second column.
Finally, I was able to achieve the result I wanted using v-html in a span inside the label slot. This works (see the third column), but it seems a bit convoluted, and it's not making the linter happy (yes, I can always turn it off).
Is there a better way to achieve this? I'm relatively new to Vue.js.
(Note that I've simplified the example for brevity, omitting id's, etc.)
<template>
<div class="m-4">
<b-container>
<b-form-row class="round-border">
<b-col
cols="4"
>
<b-form class="mr-4">
<b-form-group
v-for="(field, index) in fields"
:key="index"
:label="field.label"
>
<b-form-input
v-model.number="form[field.model]"
v-bind="field.atts"
/>
</b-form-group>
</b-form>
</b-col>
<b-col
cols="4"
>
<b-form class="mr-4">
<b-form-group
v-for="(field, index) in fields"
:key="index"
>
<label>{{ field.label }}</label>
<b-form-input
v-model.number="form[field.model]"
v-bind="field.atts"
/>
</b-form-group>
</b-form>
</b-col>
<b-col
cols="4"
>
<b-form class="mr-4">
<b-form-group
v-for="(field, index) in fields"
:key="index"
>
<label><span v-html="field.label" /></label>
<b-form-input
v-model.number="form[field.model]"
v-bind="field.atts"
/>
</b-form-group>
</b-form>
</b-col>
</b-form-row>
</b-container>
</div>
</template>
<script>
export default {
components: {},
data () {
return {
form: {
Length: 1,
Width: 4,
Height: 9
},
fields: [
{ label: 'Label<sub>1</sub>', model: 'Length', atts: { type: 'number', step: 1 } },
{ label: 'Label<sub>2</sub>', model: 'Width', atts: { type: 'number', step: 1 } },
{ label: 'Label<sub>3</sub>', model: 'Height', atts: { type: 'number', step: 1 } }
]
};
}
};
</script>
As #Ian Cho says, if the content of field.label property is html as string, the only way to solve it in vue.js is using v-html.
If you are able to change the field item structure to something like {label: 'Label', sub: 1, ...}, you can use label slot as following:
<b-form-group v-for="(f, i) in fields">
<template slot="label">{{f.label}} <sub>{{f.sub}}</sub></template>
<!-- rest of your code -->
</b-form-group>
DEMO: https://jsfiddle.net/4xmr35p0/
If you have to use HTML tags as parameter, v-html is the only way.
If there's another way, please anyone let me know. ;)
I would like to add tooltips for some of the header cells of my BootstrapVue sortable table. The table is tagged like this:
<b-table
striped
small
hover
sticky-header
sort-icon-left
selectable
id="search_results_table_id"
select-mode="single"
:items="person_list"
:fields="person_fields">
I tried to accomplish this using v-slot:head(), but wasn't able to make it work. Here is how my person_fields object is currently looking.
person_fields: [{key: 'name', label: 'Person ID', sortable: true, tooltip: 'Eureka!'},...],
And here was my v-slot:head...
Here is my v-slot:head...
<template v-slot:head()="data">
<span v-b-tooltip.hover :title='data.tooltip'>{{ data.label}}
</span>
</template>
Thanks in advance for the help!
It's because you're binding your title to an undefined property inside your slot.
The tooltip property, is nested inside a field object, which contains all the data for the field.
<template v-slot:head()="data">
<span v-b-tooltip.hover :title='data.field.tooltip'>
{{ data.label }}
</span>
</template>
I am using vue-bootstrap. I try to create dynamic a grid component that gets headers and datas. Since we will not know how many column passed to the component, we should check every item that are passed.
<template>
<b-table striped hover :items="items"></b-table>
<div v-for="title in items">
<template slot="title.key" slot-scope="data">
<input v-if="title.isActive" type="text" v-model="data.value">
<textarea v-else type="text" v-model="data.value"></textarea>
</template>
</div>
</b-table>
</template>
<script>
const items =[
{'label': 'Description', 'key': 'description'},
{'label': 'Name', 'key': 'name', 'isActive': true},
]
So, if isActive is true, then this template should be textarea(Column should be changed with textarea instead of input) However it is not working and no columns changed neither inputbox nor textarea and stay default template
Could you please help on these question.
Thank you
I think you should separate title in v-for and slot-scope variable to avoid confusing:
<template v-for="title in items" :key="title.key">
<template :slot="title.key" slot-scope="item">
<input v-if="item.isActive" type="text" v-model="item.value">
<textarea v-else type="text" v-model="item.value"></textarea>
</template>
</template>
Since, the isActive property is present inside the object in items array, you need to access it as a property of an iteratee.
So the code becomes:
<div v-for="title in items">
<template slot="{{title.key}}" slot-scope="{title}">
<input v-if="title.isActive" type="text" v-model="title.value">
<textarea v-else type="text" v-model="title.value"></textarea>
</template>
</div>
Thanks to ittus's answer,after minor modification following way is worked.
<template v-for="column in columns" :slot="column.key" slot-scope="item">
<input v-if="item.isSelect" type="text" v-model="item.value">
<textarea v-else type="text" v-model="item.value"></textarea>
</template>
Thank you all.
You can check out this example for dynamic columns.
new Vue({
el: "#app",
data: {
fields: [{
key: "id",
label: "Id",
colType: "span"
}, {
key: "name",
label: "Name",
colType: "button"
}, {
key: "uhh",
label: "uhh..",
colType: "idk"
}],
items: [{
id: 0,
name: "Test 0"
}, {
id: 1,
name: "Test 1"
}, {
id: 2,
name: "Test 2"
}]
}
});
<div id="app">
<b-table :items="items" :fields="fields">
<template v-for="(field, index) in fields" :slot="field.key" slot-scope="data">
<div v-if="field.colType === 'button'">
<h5>{{data.item.name}}</h5>
<b-button>Am Button</b-button>
</div>
<div v-else-if="field.colType === 'span'">
<h5>{{data.item.name}}</h5>
<span>Am Span</span>
</div>
<div v-else>
<h5>{{data.item.name}}</h5>
Am Confused
</div>
</template>
</b-table>
</div>
I didn't get these answers to work. Which actually helped me, was this:
https://forum.vuejs.org/t/how-to-pass-cell-templates-to-a-component-with-b-table/106283
and this fiddle:
https://jsfiddle.net/skirtle/6of9dnpz/
toCellName (slot) {
return `cell(${slot})`
}
The key is that the toCellName returns the correct slot name.
You have to use below snippet.
<input v-if="title.isActive" type="text" v-model="title.value">
<textarea v-else type="text" v-model="title.value"></textarea>
My use case.
I got an array of objects from a back-end api.
I want to render those objects in a v-select
This is my code.
<v-select
:items="categories"
name="category"
label="Select a category"
v-model="category"
v-validate="'required'"
>
</v-select>
But it gives me the output.
But I wants objects name property to be display in the v-select
We would do this in vanilla Vue.js
<li v-for="cat in categories" :key="cat.name">{{cat.name}}</li>
But here with vuetify we can't do this.
:items="categories.name"
Vuetify documentation
Can be an array of objects or array of strings. When using objects,
will look for a text and value field. This can be changed using the
item-text and item-value props.
What they actually mean by item-text and item-value
How do I achieve this using item-text
Your category has name attribute, you can pass to item-text:
<v-select
:items="categories"
v-model="category"
name="category"
v-validate="'required'"
item-text="name"
label="Select a category"
/>
I'd seen a similar solution on an example on codepen, but for some reason it did not work to merely assign the "name" to my item-text. Adding single quotes around the name attribute, thus making it a string, is what worked for me (but I don't know why that is):
<v-select v-if="categories"
:items="categories"
:item-text="'name'"
:item-value="'name'"
v-model="selectedCategory"
name="selectedCategory"
label="Select categories"
solo
dark
>
</v-select>
<script> ...
categories: [
{ name: "test", path: "test" },
{ name: "test1", path: "test1" }
],
</script>
For those still looking, the item-name and item-value props are used to specify what value to return for the name and value from the item. If you want to display only the name, but keep the entire object as the value, the return-object prop will return the entire object in the v-model.
Check out the documentation at: https://vuetifyjs.com/en/components/selects/#custom-text-and-value
<v-select :items="categories" v-model="category" name="category"
v-validate="'required'" item-text="name" return-object label="Select a category"
/>
For Vuetify 2.x use <v-slot:item> slot to customize the list and <v-slot:selection> to customize the selection. check v-select slot list in the docs
<v-select
:items="categories"
name="category"
label="Select a category"
v-model="category"
v-validate="'required'"
>
<template v-slot:item="{item}">
{{item.name}}
</template>
<template v-slot:selection="{item}">
{{item.name}}
</template>
</v-select>
To be clear here's with script
<template>
<v-select
outlined
:items="areas"
v-model="area"
name="area"
item-text="text"
label="Area"
return-object
></v-select>
</template>
<script>
export default {
data: () => ({
area: { text: 'area', disabled: false, status: false },
areas: [
{ text: 'Pre-op', disabled: false },
{ text: 'Operational', disabled: false },
{ text: 'USDA', disabled: false },
],
}),
}
</script>
I just learnt about slot today on Vue official tutorial. As I read through, I came across this example on scoped slot: https://v2.vuejs.org/v2/guide/components.html#Scoped-Slots.
I experimented a little by adding an input field to each item.
Parent:
<my-list :items="items">
<template slot="item" scope="props">
<li class="my-fancy-item">{{ props.text }}</li>
</template>
</my-list>
Child template:
<ul>
<slot name="item" v-for="item in items" :text="item.text">
</slot>
<div> // this will appear at the end of list
<input v-model = "message">
</div>
<p>{{message}}</p>
</ul>
My first attempt was to move the input to the parent scope and called a child function by passing into it the index and input value using props to modify the original array. It worked as intended.
Another attempt is to do binding on parent scope but it won't work because parent scope can't see child property: https://v2.vuejs.org/v2/guide/components.html#Compilation-Scope
What is the best way to insert this input so that it will appear in every item and still be able to bind input to child property?
Base on our discussion, I think essentially what you want is this. Because you want the message to be independently editable, it needs to be part of the item. If you make message part of my-list, then all the messages will be the same. After that, all you need to do is pass the item to the scoped template.
Vue.component("my-list",{
props:["items"],
template: "#my-list-template",
})
new Vue({
el:"#app",
data:{
items:[
{text: "item 1", message: "message 1"},
{text: "item 2", message: "message 2"},
{text: "item 3", message: "message 3"}
]
}
})
And the templates:
<div id="app">
{{items}}
<my-list :items="items">
<template slot="item" scope="props">
<li class="my-fancy-item">{{ props.item.text }}</li>
<div>
<input v-model="props.item.message">
</div>
<p>{{props.item.message}}</p>
</template>
</my-list>
</div>
<template id="my-list-template">
<ul>
<slot name="item"
v-for="item in items"
:item="item">
</slot>
</ul>
</template>
Here is the working example.