Vuetify v-date-picker throws an error when using Month first - vuejs2

I'm creating a tool where the user can change the groupings of data shown on a graph - showing it by day, week or month - by setting a range of dates using a v-date-picker.
When viewing by month, the date picker should default to a month selection, otherwise date.
The issue - If you open the v-date-picker in the month format before you have opened the date format, an error will show up in the console (RangeError: Invalid time value) once you go back to the day/week view. This does not happen if you open the day or week component first.
I've created a small snippet that replicates the issue on code pen, link below.
<div id="app">
<v-app id="inspire">
<v-row>
<v-menu ref="menu" :close-on-content-click="false" transition="scale-transition" offset-y min-width="auto">
<template #activator="{ on, attrs }">
<v-text-field v-model="dateRange" label="Date Range" prepend-icon="mdi-calendar" readonly v-bind="attrs" v-on="on" />
</template>
<v-date-picker v-model="dateRange" :show-current="false" :type="volumeType" no-title scrollable range />
</v-menu>
</v-row>
<v-row>
<v-btn #click="changeVolumeType('date')">
Date
</v-btn>
<v-btn #click="changeVolumeType('month')">
Month
</v-btn>
</v-row>
</v-app>
</div>
And the JS
new Vue({
el: "#app",
vuetify: new Vuetify(),
data() {
return {
dateRange: ["2022-10-10", "2022-10-23"],
volumeType: "date"
};
},
methods: {
changeVolumeType(newType) {
this.volumeType = newType;
}
}
});
https://codepen.io/FN_Antonie/pen/yLjrZoo - Codepen where you can replicate the issue - though you will need to open the console to see it. Try clicking on the month button first, opening the date picker, then clicking on the Date button. The console error should appear. Otherwise any other order it seems to be fine.
I've tried tracking 2 different variables and 2 different v-date-picker components, the issue still persists. I think the month picker is setting a default value that the date picker can not read, though I've tried setting explicit dates in various places but to no avail.
Any help would be greatly appreciated.

I'm guessing v-date-picker most likely wasn't meant to have a dynamic type and is breaking in this one particular case. You can get around it by adding a :key="volumeType" prop to fully rerender the date-picker when changing the type. This will also have the side effect of always resetting the dateRange values to their default value, but you can always add code to your changeVolumeType method to correctly format dateRange manually based on date or month.
<v-date-picker
v-model="dateRange"
:show-current="false"
:type="volumeType"
:key="volumeType"
no-title
scrollable
range
/>

Related

How to show default string in v-autocomplete field?

Here's my v-autocomplete component.
<v-autocomplete
v-model="selectedPlace"
:items="locationList"
:search-input.sync="query"
color="#e1b753"
clearable
item-text="title"
item-value="id"
label="Address"
return-object
required
close-on-content-click
class="pt-3 pb-0"
item-width="200"
:filter="v => v"
#change="setPlace()"
#blur="setPlace()"
>
<template v-slot:item="data">
<template>
<v-list-item-content>
<v-list-item-title v-html="data.item.title" />
</v-list-item-content>
</template>
</template>
</v-autocomplete>
When it's empty and the user first sets their address it works just fine but if they reload the page the autocomplete field is empty. I want to set its value according to user's information I get from the server but I can't figure out how.
What I've tried so far:
Set locationList[0] to the item I need and used auto-select-fist on autocomplete. It shows the needed location in the dropdown but doesn't display the value in the input.
Same as first but also set v-model to "locationList[0]". It displays the value in the input but doesn't let me change or clear it. When I select and remove the text it just jumps back in.
I guess auto-select-first should do the job, but it doesn't, am I trying to use it wrong?

Vuetify - DatePicker to select two dates only

I am having v-date-picker with multiple property. Is it possible to restrict the datepicker to select 2 dates only. Please help me out.
A simple hack could be using range instead of multiple because at the end the dates array will have only two dates when using range.
you can use range and then add rules to your v-date-picker template (example v-text-field). so it will return error if the user input is not suitable. try this rules:
visitDate: [v => this.date[0] <= this.date[1] || "Finish Date can't be earlier than Start Date"].
src: https://vuetifyjs.com/en/components/date-pickers/
Using range works in this scenario. In addition, I would like to mention the approach that I used to arrange the date in the right order.For example, Clicking on the date 2020-03-29 then clicking on 2020-03-23 will show 2020-03-29 ~ 2020-03-23.
<v-menu
ref="menu"
v-model="menu"
:close-on-content-click="false"
:return-value.sync="dates"
transition="scale-transition"
offset-y
min-width="auto"
>
<template v-slot:activator="{ on, attrs }">
<v-text-field
v-model="dateRangeText"
label="Picker in menu"
prepend-icon="mdi-calendar"
readonly
v-bind="attrs"
v-on="on"
></v-text-field>
</template>
<v-date-picker
v-model="dates"
range
no-title
scrollable
:min="new Date().toISOString().substr(0, 10)"
>
</v-date-picker>
</v-menu>
The simplest way that I found so far is to write a condition to check for the v-text-field
computed: {
dateRangeText () {
if (Date.parse(this.dates[1]) < Date.parse(this.dates[0])) {
let temp = this.dates[1]
this.dates[1] = this.dates[0]
this.dates[0] = temp
}
return this.dates.join(' ~ ')
},
},

Vuetify date picker doesn't save the correct date if i type it in my text field

Good day.
I've been using vuetify to create a form and in this form i need to select a date in which i use a date picker with a computed property to format the date. If i pick the date from the date picker calendar it works just fine however when i try typing or copy-pasting the date i get an error and it returns me whatever last date i picked on the calendar. What exactly am i doing wrong?
this is the error i get:
'Computed property "computedDateFormatted1" was assigned to but it has no setter'
Here's my date picker
<v-col cols="6">
<v-menu
ref="menu"
v-model="menu"
:close-on-content-click="false"
transition="scale-transition"
offset-y
max-width="290px"
min-width="290px"
:rules="rules"
>
<template v-slot:activator="{ on }">
<v-text-field
v-model="computedDateFormatted"
label="Emissão"
hint="Select date"
persistent-hint
prepend-icon="mdi-calendar"
v-on="on"
></v-text-field>
</template>
<v-date-picker v-model="emission" no-title #input="menu = false"></v-date-picker>
</v-menu>
</v-col>
here's my computed variables and methods:
computed: {
computedDateFormatted () {
return this.formatDate(this.emission)
},
}
methods: {
formatDate (date) {
if (!date){
return ""
} else {
const [year, month, day] = date.split('-')
return `${day}/${month}/${year}`
}
}
}
try using :value on text-field
<v-text-field :value="date">
then using vue filters.. you can check the documentation how to use it here.
https://v2.vuejs.org/v2/guide/filters.html
and then add filter at you value. for example :value="date | formatDate"
i hope it helps.

Vue/Vuetify #change doesn't provide full $event object

I'm using Vuetify in a project and creating an edit-in-place experience. Switching between the span and text field works, and it correctly sends the update to my server. One last thing though before I can call this feature complete, is that I need to determine whether the original value of the input has changed from the new value so that I'm not posting to my server when I don't need to be.
<span
v-if="editableCategory !== `category${category.id}Ref`"
class="category-header"
#click="setCategoryEditing(`category${category.id}Ref`)">
<h4>{{ category.name }}</h4>
<v-icon small>
edit
</v-icon>
</span>
<v-text-field
v-else
:ref="`category${category.id}Ref`"
:value="category.name"
color="primary"
dense
hide-details
type="text"
outlined
#blur="updateCategory(category, $event)"
#change="updateCategory(category, $event)" />
The problem is that when when I console log the $event, I get two different responses when testing the #change and the #blur. The #blur seems to give me the normal, full event object and I am then able to compare old and new values correctly. However, the #change event simply gives me a string of the new value.
Is this an issue with the Vuetify v-text-field #change event not firing correctly (and I should therefore create a Github issue with them?), or am I totally misunderstanding blur/change events (also another very real possibility)?
Blur event usually returns the event from the element attached. But the change event returns the updated value from the input element
but still you can able to read the updated value from the blur event using the below approach
Working codepen here, check the console for expected output: https://codepen.io/chansv/pen/JjjaZOJ?editors=1010
<div id="app">
<v-app id="inspire">
<v-form>
<v-container>
<v-row>
<v-col cols="12" sm="6" md="3">
<v-text-field
label="Outlined"
placeholder="Placeholder"
outlined
#change="updateCategory($event, category)"
#blur="updateCategory($event.target.value, category)"
></v-text-field>
</v-col>
</v-row>
</v-container>
</v-form>
</v-app>
</div>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: {
category: 'category text',
},
methods: {
updateCategory(event, category) {
console.log(event, category);
},
}
})

Vue.js / Vuetify / v-data-table: item from v-slot seems to be a copy and not a reference for the attribute

I'm creating a data table with Vuetify to show a list of records, where each record has a list of files to download. Then, I'm creating a button, for each table row, that when it is clicked, it should show a modal with the list of files.
The list is called tableRows and it has several objects. I provide an example below.
script
export default {
data () {
return {
tableRows: [
{
'properties': {
'date': '2015-12-19',
'title': 'LC82200632015353LGN01',
'type': 'IMAGES',
'showDownloadDialog': false
},
'provider': 'DEVELOPMENT_SEED'
},
...
],
showDownloadDialog: false // example
}
}
}
The table is built well, but I'm not capable to use the modal for each table row.
The modal example on the site works well, where I use just one variable (i.e. dialog) and I want to show just one single modal, however in my case, I have a list of objects, where each object may open a specific modal.
I've tried to put the showDownloadDialog attribute in each object from my list and bind it using v-model (v-model='props.item.properties.showDownloadDialog'), but to no avail. The modal does not open.
template
<v-data-table :items='tableRows' item-key='properties.title'>
<template v-slot:items='props'>
<tr class='tr-or-td-style-border-right'>
<td class='text-xs-left th-style-height'>
<div class='text-xs-center'>
...
<!-- Download button -->
<br>
title: {{ props.item.properties.title }}
<br>
showDownloadDialog: {{ props.item.properties.showDownloadDialog }}
<br>
<v-btn #click.stop='props.item.properties.showDownloadDialog = true' title='Show download list'>
<i class='fas fa-download'></i>
</v-btn>
<v-dialog v-model='props.item.properties.showDownloadDialog' persistent scrollable max-width="600">
<v-card>
...
<v-card-actions>
<v-btn #click='props.item.properties.showDownloadDialog = false'>
Close
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</td>
</tr>
</template>
</v-data-table>
I've tried to print on the page the attribute props.item.properties.showDownloadDialog and it does not change when I click on the button. I believe this attribute is not reactive, because of that, its state does not change, but I don't get why it is not reactive. The props from data table seems to be a copy and not a reference for one record in my list tableRows.
example
I've already tried to add a simple flag in data () called showDownloadDialog, instead of using props.item.properties.showDownloadDialog, and it works, but it shows all the modals at the same time, not just the specific modal related to that record, unfortunately.
Would anyone know what can be happening?
Thank you in advance.
I was able to fix my problem by using Subash's help. I give the code below.
First, I've inserted a new property in my data (). I will use this property to show/close my modal and provide information to fill it.
downloadDialog: {
show: false
}
Inside data table I just let the button and I've created a method called showDownloadDialog where I pass the properties object (i.e. where the information is).
<v-btn flat icon color='black' class='v-btn-style'
#click='showDownloadDialog(props.item.properties)' title='Show download list'>
<i class='fas fa-download'></i>
</v-btn>
Outside data table, I've added v-dialog and I've bound it with downloadDialog.
In addition to it, I've created a method to close the dialog.
<v-dialog v-model='downloadDialog.show' persistent scrollable max-width="600">
<v-card>
...
<v-card-actions>
<v-btn #click='closeDownloadDialog()'>
Close
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
Inside the showDownloadDialog I merge 'properties' into 'downloadDialog' and I open the modal, while closeDownloadDialog I just close the modal.
showDownloadDialog (properties) {
// merge 'properties' into 'downloadDialog'
Object.assign(this.downloadDialog, properties)
this.downloadDialog.show = true
},
closeDownloadDialog () {
this.downloadDialog.show = false
}
Thank you so much Subash for your help.