How to bind a Date object to an input date using vue.js? (v-model doesn’t work)
If you really want to use v-model
you have to create a custom component (see below in the second part of this post).
But there is also a more direct alternative. Considering myDate
is your property, you could just use:
<input type="date" :value="myDate && new Date(myDate.getTime()-(myDate.getTimezoneOffset()*60*1000)).toISOString().split('T')[0]"
@input="myDate = $event.target.valueAsDate">
OR
<input type="date" :value="dateToYYYYMMDD(myDate)"
@input="myDate = $event.target.valueAsDate">
<!-- see code for dateToYYYYMMDD method below -->
With dateToYYYYMMDD()
being
methods:
// ...
dateToYYYYMMDD(d) {
// alternative implementations in https://stackoverflow.com/q/23593052/1850609
return d && new Date(d.getTime()-(d.getTimezoneOffset()*60*1000)).toISOString().split('T')[0]
}
Full demo, as well as discussion of this and the component solution below.
Breakdown of the solution
Since v-model
is only syntactic sugar to :value
and @input
, you can use these two attributes instead of v-model
. In this case, we used them because we want to change their behavior a little (to format the String
that is the output of the date input to a Date
object and vice-versa).
Check a JSFiddle Demo of the code below.
<script src="//unpkg.com/vue@2.6.11/dist/vue.min.js"></script>
<div id="app">
<p>
Formatting the date in the template:
<input type="date" :value="myDate && new Date(myDate.getTime()-(myDate.getTimezoneOffset()*60*1000)).toISOString().split('T')[0]"
@input="myDate = $event.target.valueAsDate">
</p>
<p>
Formatting the date using a helper method:
<input type="date" :value="dateToYYYYMMDD(myDate)"
@input="myDate = $event.target.valueAsDate">
</p>
<p>
<code>
myDate: {{ myDate }}</code>
</p>
<button @click="setMyDateToToday">Set date one to today</button>
<button @click="addADayToMyDate">Add a day to my date</button>
</div>
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
myDate: new Date('2011-04-11T00:01:01Z') // DO notice this date is set in UTC (Greenwich time) not your current timezone
},
methods: {
setMyDateToToday() {
this.myDate = new Date();
},
addADayToMyDate() {
// use the if because myDate can be null
if (this.myDate) {
// notice we don't just call .setDate(...) in myDate, instead
// we create a new Date object and set it to this.myDate, so vue can detect it changed
// this is not a caveat of this specific solution, but of any binding of dates
this.myDate = new Date(this.myDate.setDate(this.myDate.getDate() + 1));
}
},
dateToYYYYMMDD(d) {
// alternative implementations in https://stackoverflow.com/q/23593052/1850609
return d && new Date(d.getTime()-(d.getTimezoneOffset()*60*1000)).toISOString().split('T')[0]
}
}
});
// Notes:
// We use `myDate && new Date(myDate.getTime()-(myDate.getT...` instead
// of just `new Date(myDate.getTime()-(myDate.getT...` because `myDate` can be null.
Again, the executable JSFiddle Demo is here.
Creating a custom input-date
component and using v-model
If you want to stick to the v-model
, you can use the code below. The component below is also a useful demonstration of a component that binds to the value
property of a HTML input
.
Check a JSFiddle Demo of the code below.
<script src="//unpkg.com/vue@2.6.11/dist/vue.min.js"></script>
<div id="app">
myDate: <input-date v-model="myDate"></input-date>
<p>myDate: {{ myDate }}</p>
<button @click="setMyDateToToday">Set date one to today</button>
<button @click="addADayToMyDate">Add a day to my date</button>
</div>
Vue.component('input-date', {
template: `
<input
type="date"
ref="input"
v-bind:value="dateToYYYYMMDD(value)"
v-on:input="updateValue($event.target)"
v-on:focus="selectAll"
>
`,
props: {
value: {
type: Date,
default: new Date()
}
},
methods: {
dateToYYYYMMDD(d) {
// alternative implementations in https://stackoverflow.com/q/23593052/1850609
return d && new Date(d.getTime()-(d.getTimezoneOffset()*60*1000)).toISOString().split('T')[0];
},
updateValue: function (target) {
this.$emit('input', target.valueAsDate);
},
selectAll: function (event) {
// Workaround for Safari bug
// http://stackoverflow.com/questions/1269722/selecting-text-on-focus-using-jquery-not-working-in-safari-and-chrome
setTimeout(function () {
event.target.select()
}, 0)
}
}
});
new Vue({
el: '#app',
data: {
myDate: new Date('2011-04-11T00:00:01Z') // DO notice this date is set in UTC (Greenwich time) not your current timezone
},
methods: {
setMyDateToToday() {
this.myDate = new Date();
},
addADayToMyDate() {
// use the if because myDate can be null
if (this.myDate) {
// notice we don't just call .setDate(...) in myDate, instead
// we create a new Date object and set it to this.myDate, so vue can detect it changed
// this is not a caveat of this specific solution, but of any binding of dates
this.myDate = new Date(this.myDate.setDate(this.myDate.getDate() + 1));
}
}
}
});
// Notes:
// We use `myDate && new Date(myDate.getTime()-(myDate.getT...` instead
// of just `new Date(myDate.getTime()-(myDate.getT...` because `myDate` can be null.
Leave a Comment