Vuetify - DatePicker to select two dates only - vue.js

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(' ~ ')
},
},

Related

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

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
/>

Select All functionality to select filtered items in vuetify combobox

I'm using vuetify combobox and the select all is working as expected as described in How to have a "select all" option on a v-select or v-combobox?.
What I'm trying to achieve is - when I check the Select All, it should select all the filtered values from the list.
In this example, I've typed "Pha..." and what I'm trying to achieve is to get the filtered list to be returned.
The Combobox is as below -
<v-combobox v-if="editedIndex == -1"
label='Phase'
v-model='editedItems.selected_values'
:items='phases'
item-value='pp_code'
item-text='phasedetails'
class="pl-2 pr-2"
multiple
chips
>
<template v-slot:prepend-item>
<v-list-item
ripple
#click="toggle(); editedItems.selected_values.length = phases.length;"
>
<v-list-item-action>
<v-icon :color="editedItems.selected_values.length > 0 ? 'indigo darken-4' : ''">
{{ icon }}
</v-icon>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>
Select All
</v-list-item-title>
</v-list-item-content>
</v-list-item>
<v-divider class="mt-2"></v-divider>
</template>
</v-combobox>
The toggle function is as below -
toggle () {
this.$nextTick(() => {
if (this.likesAllFruit) {
console.log("Select all clicked")
this.selectedFruits = []
console.log("Typed value is ")
console.log(this.editedItems.phase_code)
console.log("Selected values ")
console.log(this.editedItems.selected_values)
this.alreadySelectedPhases.push(this.editedItems.selected_values)
console.log(this.alreadySelectedPhases)
console.log(this.phases.length)
} else {
this.editedItems.selected_values = this.phases.slice()
}
})
},
I'm not getting the typed value until the combobox is selected so that we can filter the list by the typed value and return.
Please let me know if anyone has any idea on how we can achieve it. Or if we have any inbuilt method for it.
Thanks in Advance.

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.

how to handle a dropdown visibility manually instead of Vuetify controls this

I have created a dropdown menu in vuetify which looks like this:
[![enter image description here][1]][1]
`
<v-menu offset-y>
<template v-slot:activator="{ on }">
<v-btn text v-on="on">
Details
</v-btn>
</template>
<v-list>
<v-list-item>
<v-form ref="form">
<v-radio-group v-model="metrics" required>
<v-radio
label="ABC"
value="abc"
></v-radio>
<v-radio label="XYZ" value="xyz"></v-radio>
</v-radio-group>
<v-divider></v-divider>
<v-radio-group v-model="order" required>
<v-radio
label="Higher"
value="higher"
></v-radio>
<v-radio
label="Lower"
value="lower"
></v-radio>
</v-radio-group>
<v-divider></v-divider>
<v-btn
#click="
sortTableData(
metrics,
order,
$props.tableItems
)
"
>
Apply
</v-btn>
</v-form>
</v-list-item>
</v-list>
</v-menu>`
however,
when I click the Dropdown and select for eg:Installs, the menu
closes..
I have to click the Dropdown again to choose higher/lower..
and the menu closes again..
And again I have to click the Dropdown to Click "Apply" button.
Question : Is there Any way I can hold this menu until I click "Apply"?
Thanks a lot in advance for your help !
Ok, the idea here is to manually handle the dropdown visibility instead of letting Vuetify controls this.
To do so, you need to:
add a :close-on-content-click="false" on your <v-menu> (doc)
add a v-model directive binded to a "data" boolean value (ex: v-model="isDropdownDisplayed"), initialized to false (closed dropdown at load)
The first prop tells Vuetify to not close the dropdown when clicking on content (only an outside click will do it), while the second prop is linking the dropdown visilibity to your custom data boolean value.
As your "data" boolean value is initialized to false (closed dropdown) and is automatically updated to true via the v-model when opening the dropdown, the left thing to do is to pass this value to false on your sortTableData method.
Assuming you're using SFC (but the approach is the same for pure JS components):
Template
<v-menu offset-y :close-on-content-click="false" v-model="isDropdownDisplayed">
...
</v-menu>
Script
{
name: 'MyComponent',
data: function () {
return {
isDropdownDisplayed: false
}
},
methods: {
sortTableData: function (/* args */) {
// ...
this.isDropdownDisplayed = false
// ...
}
}
}

Vuetify Datatable - Rendering element on first row only

i have a problem on a vue project of mine.
i have a vuetify datatable that receives data from a .net core backend with mongo.
it works just fine and every row have a edit and delete buttons. but in this case i need to limit edit and delete buttons to show only on the first row of the datatable.
i've tried a lot of solutions from the internet but none of them worked for me so far.
here's the code for the datatable and the buttons, respectively:
<v-data-table
:headers="headers"
:items="pacientes"
:search="search"
:page.sync="page"
:items-per-page="itemsPerPage"
hide-default-footer
sort-by="status"
class="elevation-1"
#page-count="pageCount = $event"
>
<template
v-slot:item.edit="{ item }" >
<v-btn
color="blue"
tile
x-large
icon
#click="aprovar(item.nomePaciente, item.idEspera, item.matricula)"
>
<v-icon>mdi-pencil-circle</v-icon>
</v-btn>
</template>
<template
v-slot:item.delete="{ item }"
>
<v-btn
color="red"
x-large
tile
icon
#click="abrirModalDeletar(item.nomePaciente, item.idEspera)">
<v-icon>mdi-delete-circle</v-icon>
</v-btn>
</template>
Any help would be appreciated, thanks!
You could introduce a boolean property to your items in the array, let's call it isFirst Then you could listen to the event of current-items in the data table, which returns the current items in view. And based on that, show the buttons for the first row. So I suggest the following:
<v-data-table #current-items="setFirst" ...... >
And the function:
methods: {
setFirst: function(currItems) {
// first check that actually exists values
if (currItems.length) {
// toggle all to false
currItems.forEach(x => x.isFirst = false)
// just set first to true
currItems[0].isFirst = true;
}
}
},
and then set an v-if to the buttons:
<v-btn v-if="item.isFirst" ....>
CODEPEN
If your object has an ID and you know what that ID is, you can set a v-if statement for your edit and delete buttons to only render when the ID is equal to that value. Something like this:
<template
v-slot:item.edit="{ item }" >
<v-btn
color="blue"
tile
v-if="item.id===1"
x-large
icon
#click="aprovar(item.nomePaciente, item.idEspera, item.matricula)"
>
<v-icon>mdi-pencil-circle</v-icon>
</v-btn>
</template>
<template
v-slot:item.delete="{ item }"
>
<v-btn
color="red"
x-large
tile
v-if="item.id===1"
icon
#click="abrirModalDeletar(item.nomePaciente, item.idEspera)">
<v-icon>mdi-delete-circle</v-icon>
</v-btn>
</template>
If your item doesn't have an ID, when you fetch your data, you can programmatically set a property on the first item and then use the v-if statement on that property.
Something like:
fetchData().then(items => {
if (items.length >= 1) {
items[0].showEditDelete = true
}
})
Then your v-if statement will look like v-if=item.showEditDelete.