Vuetify + Vuex + vuex-map-fields: v-data-table with a v-select - vue.js

I have a v-data-table, and one of the columns is a v-select
The data is stored in vuex, and I use vuex-map-fields to retrieve/update
The UI is (simplified)
<v-data-table
:items="data"
>
<template v-slot:item.type="{ item }">
<v-select
v-model="?"
:items="types"
item-text="description"
/>
</template>
</v-data-table>
And the data is (simplified)
data: [
{
.
.
type: <some_uuid_1>
},
{
.
.
type: <some_uuid_2>
}
],
types: [
{
id: <some_uuid_1>,
description: "first"
},
{
id: <some_uuid_2>,
description: "second"
}
]
What I am trying to do
I'm tring to "map" the v-model of the v-select in such a way that the root data object (data) is updated correctly.emphasized text
Rephrased
If I pick from the v-select in any row in the v-data-table the corresponding item in data is updated
Notes: vuex-map-fields is a library that saves me writing getters/mutations

Ok it's a mixup with the vue chrome devtools, the state wasn't updating in the vue extension but it actually is being updated. (should I just delete the question?)

Related

Vue bootstrap table: button in column not rendering

I have a Vue Bootstrap table with a "cosimo" column that includes a button to launch a modal. However, the button is not rendering properly and does not work when clicked. Here is the code for the column:
columns: [
{
title: "Cosimo",
field: "component.name",
sortable: true,
formatter: (value, row, index) => {
return `
<b-button v-b-modal.modal-1 #click="showModal"
>Launch demo modal</b-button
>
`;
}
}, ...]
I've checked the Vue Bootstrap documentation and I believe I've followed the correct syntax for creating a button that launches a modal. However, the button is not working and the HTML is not rendering properly. Can anyone help me identify the issue? Thanks in advance! It works outside the table in the template part.
EDIT
I am rendering the column with this code:
<bootstrap-table
ref="table"
:columns="columns"
:data="data"
:options="options"
#on-load-success="tableLoaded"
>
<template v-slot:cell(component.name)>
<span><b-btn #click="showModal(item)">Launch Demo Modal</b-btn></span>
</template>
</bootstrap-table>
And then the columns entry:
{
title: "Cosimo Recommendation",
field: "component.name",
sortable: true
},
I'm not sure which version of bootstrap-vue you're using, but if you're on version 2.23.0, then you can use slots for adding buttons and other HTML elements, see below example of info model button in documentation:
https://bootstrap-vue.org/docs/components/table#complete-example
You can achieve this by using slot in the template itself for that particular column.
<b-table :items="items" :fields="fields">
<template v-slot:cell(<component.name>)="{ item }">
<span><b-btn #click="showModal(item)">Launch Demo Modal</b-btn></span>
</template>
</b-table>
You can see cell({key}) slot here

Is it possible to use dynamic scoped slots to override column values inside <v-data-table>?

I'm trying to create a reusable table component that utilizes Vuetify's v-data-table component in order to group common aspects such as a search bar, table actions (refresh, create, etc.) and other features that all of my tables will have. However, I'm running into issues with implementing dynamic, scoped slots inside the table component to account for custom columns. Think of columns like actions, formatted ISO strings, etc.
Here's a simplified example of what I'm trying currently. In the example, I am passing the array customColumns to CustomDataTable.vue as a prop. customColumns has one element with two properties. The slotName property specifies the name of the slot that I'd like to reference in the parent component. The itemValue property specifies the header value that CustomDataTable.vue should override and replace with a scoped slot. The scoped slot is then used in the parent component to correctly format the date in the 'Created At' column.
Parent Component that is implementing the table component:
<template>
<custom-data-table
:items="items"
:headers="headers"
:customColumns="customColumns"
>
<template v-slot:custom-column="slotProps">
<span>{{ formatDate(slotProps.item.createdAt) }}</span>
</template>
</custom-data-table>
</template>
<script>
import CustomDataTableVue from '#/components/table/CustomDataTable.vue'
export default {
data: () => ({
items: [
{
id: 0,
createdAt: new Date().toISOString(),
...
},
...
],
headers: [
{
text: 'Created At',
value: 'createdAt',
sortable: true
},
...
],
customColumns: [
{
slotName: 'custom-column',
itemValue: 'createdAt'
}
]
})
}
</script>
CustomDataTable.vue
<template>
<v-data-table
:items="items"
:headers="headers"
>
<template v-for="column in customColumns" v-slot:item[column.itemValue]="{ item }">
<slot :name="column.slotName" :item="item"/>
</template>
</v-data-table>
</template>
<script>
export default {
name: 'custom-data-table',
props: {
items: {
type: Array,
required: true
},
headers: {
type: Array,
required: true
},
customColumns: {
type: Array
}
}
}
</script>
Is there a way to achieve this? The example does not override the column values and just displays the createdAt ISO string unformatted. I believe the problem might be coming from how I'm assigning the template's slot in CustomDataTable.vue, but I'm sure how else you could dynamically specify a template's slot. Any ideas?
I think the syntax for dynamic slots should be:
<template
v-for="column in customColumns"
v-slot:[`item.${column.itemValue}`]="{ item }"
>
<slot :name="column.slotName" :item="item"/>
</template>

Vue: Unknown custom element after adding component reference within component

I'm new to Vue and testing vue-draggable component. Once I add reference to vue-draggable component, I get the error "Unknown custom element: < fxm-form> - did you register the component correctly? For recursive components, make sure to provide the "name" option."
What am I missing here? Similar threads earlier does not have component referenced within a component.
import draggable from "./vue-draggable";
Vue.component('fxm-form', {
name: 'fxm-form',
props: [
"formMode"
],
components: {
draggable
},
data() {
return {
list: ['AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF']
}
},
mounted() {
},
methods:
{
},
template: `
<div>
<h1>Dragable Test</h1>
<draggable :list="list" class="drag-container">
<div v-for="item in list" class="drag-item">{{ item }}</div>
</draggable>
</div>
`
});
When you create a component with Vue.component(), it registers components globally.
As per official docs:
global registration must take place before the root Vue instance is created (with new Vue)
This is because either you've not initialized your component before Vue Instance.
You can register your component inside you Vue Instance.
Here is the working codesandbox example

Vuetify v-text-field Default Slot Not Working

I am trying to use a custom filter with the Vuetify v-text-field control. I am having trouble getting a value to show using the default slot of the v-text-field control. It is apparently derived from v-input, which seems to work fine.
This does not work:
<v-text-field>
{{ purchasePrice | currency }}
</v-text-field>
This works:
<v-input>
{{ purchasePrice | currency }}
</v-input>
Am I missing a template slot or something? I've been able to successfully use the "append" and "prepend" slots on this control, but not the "default" slot. Any suggestions?
Thanks.
I just ran into this as well, and did some source diving. Documenting my findings below:
As of Vuetify 2.5.8 (most recent version), and any other 2+ version, default slot is ignored on v-text-element.
The relevant part in the source code of VTextField.ts:
genDefaultSlot () {
return [
this.genFieldset(),
this.genTextFieldSlot(),
this.genClearIcon(),
this.genIconSlot(),
this.genProgress(),
]
},
it overrides genDefaultSlot method of VInput.ts, which is included as a mixin in VTextField.ts:
genDefaultSlot () {
return [
this.genLabel(),
this.$slots.default,
]
},
I could only make it work with named slots: (Also, I'm reusing this component, so it accepts another slot on the inside)
<template>
<v-layout>
<v-text-field
:type="type"
v-bind="
// https://vuejs.org/v2/guide/components-props.html#Disabling-Attribute-Inheritance
$attrs
"
#input="$emit('update', $event)"
v-on="
// https://vuejs.org/v2/guide/components-custom-events.html#Binding-Native-Events-to-Components
$listeners
"
>
<!-- ⬇️ HERE ⬇️ -->
<template v-slot:label>
<slot></slot>
</template>
</v-text-field>
</v-layout>
</template>
<script>
import { defaultMaterialTextFiledsProps } from '~/config/inputsStyle'
// See https://github.com/chrisvfritz/vue-enterprise-boilerplate/blob/master/src/components/_base-input-text.vue
export default {
// Disable automatic attribute inheritance, so that $attrs are
// passed to the <input>, even if it's not the root element.
// https://vuejs.org/v2/guide/components-props.html#Disabling-Attribute-Inheritance
inheritAttrs: false,
props: {
type: {
type: String,
default: 'text',
// Only allow types that essentially just render text boxes.
validator(value) {
return [
'email',
'number',
'password',
'search',
'tel',
'text',
'url'
].includes(value)
}
}
}
}
</script>

How to preselect in Vue multiple select js

This is the markup for my veu multiselect
and here is the code
<multiselect
v-model="baths"
placeholder="Bath"
track-by="label"
label="label"
:allow-empty="true"
:options="options.baths"
:select-label="''"
:selected-label="''"
:deselect-label="'Remove'"></multiselect>
Just populate the baths data property with the data you wanted to be preselected.
data: {
baths: [],
options: {
baths: [
// baths list here
]
}
},
mounted() {
this.baths.push(this.options.baths[1]);
}
Also you need to set the multiple prop to true:
<multiselect
v-model="baths"
placeholder="Bath"
track-by="label"
label="label"
:allow-empty="true"
:options="options.baths"
:select-label="''"
:selected-label="''"
:deselect-label="'Remove'"
:multiple="true">
</multiselect>
See this example JS Fiddle:
https://jsfiddle.net/0hLexkyz/278/