Can today's date be disabled in <v-date-picker>? - vue.js

I'd like to disable today's date and all dates after. I managed to disable every day after today so far.
<v-date-picker>
class="date-picker-header"
v-model="dateTo"
#input="menuTo = false"
:disabledDates="date.getDate()"
:max="new Date().toISOString().substr(0, 10)"
I tried :max, :min, and several methods allowing "<=" and ">=" options when returning the date. I'm still only able to disable dates before or after today, but not today.

Just use :min="tomorrow"?
data() {
const today = new Date()
return { tomorrow: new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1)
}
}
Or use the :allowed-date prop to allow everything except for today:
<v-date-picker :allowed-dates="allowedDates" />
methods: {
allowedDates(date) {
return !isToday(date)
}
}

<template>
<v-date-picker v-model="dateTo" :max="maxDateAllowed"></v-date-picker>
</template>
computed: {
maxDateAllowed() {
const d = new Date()
const endDate = new Date(d.getFullYear(), d.getMonth(), d.getDate() - 1);
return endDate.toISOString().slice(0,10)
}
}

Related

Vuejs: how to implement reactively disable datepicker

im newbie here. I want control the datepicker to be disabled automatically based on the existing api. I using the vuejs-datepicker library. I've seen the documentation and managed to implement it statically, but having problems when implementing it reactively.
This is my previous view:
<datepicker
:disabled-dates="state.disabledDates">
</datepicker>
And, my previous static value of datepicker, especially for the day:
data() {
var year = (new Date()).getFullYear()
var month = (new Date()).getMonth()
var dDate = (new Date()).getDate()
var state = {
disabledDates: {
to: new Date(year, month, dDate), // Disable all dates up to specific date
// from: new Date(2020, 0, 26), // Disable all dates after specific date
days: [0,1], // Disable Saturday's and Sunday's
}
}
return {
state: state,
day: '',
}
},
For now, here my view:
<datepicker
:disabled-dates="disabledDates">
</datepicker>
Console output:
My script:
<script>
data() {
return {
day: '',
year : (new Date()).getFullYear(),
month : (new Date()).getMonth(),
dDate : (new Date()).getDate(),
}
},
computed:{
// reactive
disabledDates: {
to: new Date(year, month, dDate), // Disable all dates up to specific date, 2020,8,8
days: [day], // Disable day, 0,1
}
},
watch: {
'day': function(day){
console.log('day: '+day)
return this.day
},
},
</script>
Thank you.
I'm pretty sure your only problem is that your syntax for computed properties is wrong. They should be functions, since they need to be run. Their dependencies are automatically determined by Vue, and when those change, the function is re-run. So, try this:
data: function() {
return {
day: '',
year: (new Date()).getFullYear(),
month: (new Date()).getMonth(),
dDate: (new Date()).getDate()
};
},
computed: {
// Here. This should be a function.
disabledDates: function() {
return {
// Make sure to use 'this.' when in a component
to: new Date(this.year, this.month, this.dDate),
days: [ this.day ]
};
}
},
watch: {
day: function(day) {
console.log(`Day: ${day}`);
return value;
}
}

Countdown variable (HH:mm:ss)

I parse a date YYYY-mm-dd and calculate the difference till midnight. The result will be always under 24h, for example 10:01:10 - HH:mm:ss till it expires. I wonder how I could achieve a countdown functionality with the given example.
<template>
<Label :text="date.expires | readableTime"></Label>
</template>
filters: {
readableTime(value) {
var now = moment(new Date());
var end = moment(value);
var diff = moment.duration(end.diff(now));
try {
return moment.utc(diff.as("milliseconds")).format("HH:mm:ss");
} catch (e) {
return "00:00:00";
}
}
}
You must use use timer and reactive data property. I recommend you to safe diff to components data, start timer on component mount and clear it beforeDestroy
data() {
return {
diff: this.calculareDiff()
}
}
methods: {
calculareDiff() {
const now = moment(new Date());
const end = moment(this.date.expires);
this.diff = moment.duration(end.diff(now));
}
},
mounted() {
this.timer = setInterval(() => this.calculareDiff(), 1000)
},
beforeDestroy() {
clearInterval(this.timer)
}

How Do I update the Dom (Re-render element) when value changes?

So I have a variable startWeek, that is being displayed and when I click a button, a Have a method that will add 7 days to the date. I want the page to show the new date but not sure how to go about doing this?
I want to get the dates to transition in and out everytime the date range is updated, but Im not sure how to do it. I have thought about using two v-if statements and transitioning back and fourth between them but im sure there is a better way. I have looked into watchers and computed properties but im not quite sure if they are the answer or how to implement them in this given situation.
Example:
<template>
<b-button #click="subtractWeek(7)></b-button>
<span id="thingIwantToUpdateInDOM">{{ startWeek + " - " + endWeek}}</span>
<b-button #click="addWeek(7)></b-button>
</template>
export default {
data(){
return{
startWeek: null,
endWeek: null,
}
},
methods: {
addWeek(days){
this.startWeek.setDate(this.startWeek.getDate() + days)
this.endWeek.setDate(this.endWeek.getDate() + days)
},
substractWeek(7){
this.startWeek.setDate(this.startWeek.getDate() - days)
this.endWeek.setDate(this.endWeek.getDate() - days)
},
getInitialDate(){
this.startWeek = new Date();
var tempEndWeek = new Date();
this.endWeek = tempEndWeek;
},
created() {
this.getInitialDate();
}
}
}
My ultimate goal is to have the date range to swipe our transition out similar to a carousel effect on every button click or value change. Any bit of advise is greatly appreciated!
Your end goal is lots of optimizations away, but the snippet below should get you started. Your date operations are fine, so a few notes about the implementation:
I don't exactly know the internals of how Vue does state change tracking in the data objects, but I'm fairly sure it involves getter and setter property accessors. When you do this.x = new Date(); this.x.setDate(this.x.getDate() + 7);, this.x tracks the date object and not its value, so the change will not be seen by Vue. You need to clone the date first, set a new date, and then reassign it to this.x (see the navigateWeeks method below).
watch is useful when you want to react to a single, specific property change, in your case, the dynamic startWeek is a perfect candidate. If the fact that something changed is more important than what exactly, use the updated hook (typical use-case: destroying & re-initializing 3rd party library widgets with new parameters).
computed is useful for keeping a property derived from another property in sync at all times, in your example the endDate is always 7 days after the startDate, so it is a perfect candidate for this. In the snippet I also used a computed value for the ISO date format that HTML date inputs expect.
Finally, you can do quite advanced stuff with setTimeout, some CSS keyframes, and toggling a .transitioning class
Vue.component('fading-date', {
template: `
<span><input :class="className" type="date" :value="htmlValue"></span>
`,
props: {
value: { type: Date },
fadeDuration: { type: Number, default: 1 }
},
data() {
return { transitioning: false, timer: null };
},
computed: {
htmlValue() {
return this.value.toISOString().split('T')[0];
},
className() {
return this.transitioning ? 'transitioning' : '';
}
},
watch: {
value() {
clearTimeout(this.timer);
this.transitioning = true;
this.timer = setTimeout(() => {
this.transitioning = false;
}, 1000 * this.fadeDuration);
}
}
});
new Vue({
el: '#app',
data: {
selectedWeek: new Date()
},
computed: {
weekAfterSelected() {
const date = this.selectedWeek;
const endDate = new Date(date);
endDate.setDate(date.getDate() + 7);
return endDate;
}
},
methods: {
navigateWeeks(numWeeks = 1) {
const newDate = new Date(this.selectedWeek);
newDate.setDate(newDate.getDate() + (7 * numWeeks));
this.selectedWeek = newDate;
}
}
});
input[type="date"] {
background: transparent;
border: none;
}
#keyframes fade{
0% {
opacity:1;
}
50% {
opacity:0;
}
100% {
opacity:1;
}
}
.transitioning {
animation: fade ease-out 1s;
animation-iteration-count: infinite;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<fading-date :value="selectedWeek" :fade-duration="1"></fading-date>
<fading-date :value="weekAfterSelected" :fade-duration="1"></fading-date>
<br>
<button type="button" #click="navigateWeeks(-1)">A week sooner</button>
<button type="button" #click="navigateWeeks(1)">A week later</button>
</div>

Vue2 Element-UI Datepicker force refresh for dynamic disabledDate

In the codepen below I have a Element-UI datepicker set up to show a dynamic disabled dates based on a random number.
The number of disabled dates change every time the datepicker input comes into focus.
My issue is the datepicker doesn't refresh the disabled dates until you click on a different month. The datepicker also shows the last month you were previously on when when you click off and back in.
Is there a way to force Element-UI Datepicker to refresh? I would like to make the datepicker refresh in the on focus event after the new disabled value is set.
https://codepen.io/anon/pen/rbXjLr
Element-UI Datepicker Documentation
<div id="app">
<template>
<div class="block">
<span class="demonstration">Picker with quick options</span>
<el-date-picker
v-model="value2"
type="date"
placeholder="Enter Date"
#focus="focus()"
:default-value="defaultValue"
:picker-options="pickerOptions">
</el-date-picker>
</div>
</template>
</div>
var is10Days = "";
var Randomizer = (function(){
var is10DaysSetter = function(){
if(is10Days === "") {
is10Days = Math.round(Math.random()) === 1;
}
//console.log("is10Days: " + is10Days);
return is10Days;
}
return {
Is10DaysSetter: is10DaysSetter
}
})()
var Main = {
data() {
return {
defaultValue: "",
pickerOptions: {
disabledDate(time) {
var self = this;
var date = moment()._d;
var mindate = moment().subtract(5,'d')._d;
var maxDate = moment()._d;
var isBeforeMinDate = time.getTime() < mindate;
var isAfterMaxDate = time.getTime() > maxDate;
if(is10Days !== "" && is10Days){
var alternateMinDate = date.setDate(date.getDate() - 10);
isBeforeMinDate = time.getTime() < alternateMinDate;
}
//console.log("disabledDate");
return isBeforeMinDate || isAfterMaxDate;
}
},
value2: '',
};
},
methods:{
focus: function() {
var self = this;
is10Days = "";
self.defaultValue = moment().format("YYYY-MM-DD");
Randomizer.Is10DaysSetter();
console.log("reset is10Days: " + (is10Days ? "10 days" : "5 days"));
}
}
};
var Ctor = Vue.extend(Main)
ELEMENT.locale(ELEMENT.lang.en)
new Ctor().$mount('#app')
I posted this as a feature request on Element UI's git hub and received a response:
https://github.com/ElemeFE/element/issues/15380
<el-date-picker
ref="picker" //Added this
v-model="value2"
type="date"
placeholder="Enter Date"
#focus="focus()"
:picker-options="pickerOptions">
</el-date-picker>
methods:{
focus: function() {
var self = this;
is10Days = "";
Randomizer.Is10DaysSetter();
//Added this
this.$nextTick(_ => {
this.$refs.picker.picker.date = new Date()
})
console.log("reset is10Days: " + (is10Days ? "10 days" : "5 days"));
}
}
Adding a reference to picker allowed me to override the unwanted feature of going back to the previously viewed month and solved my issue. This came with a warning that since this is not part of the public API, it could change in a future version.
Here is a link to a working code pen:
https://codepen.io/steveshore/pen/rbXjLr
I think it is about compomemt render. when your main vue app initialize, <el-date-picker>
rendered completly first.
The problem is when date-picker finished rendering, are the main vue datas ready?
It seems you pass a null into options, but select another month will force update options.
could you try this?
How to Initialize Data Properties with Prop Values
make a v-if="pickerOptions" in attr

How to Set minimum and maximum date dynamically in Element-ui date picker

I am having 2 date pickers for startDate and endDate.
In startDate Picker,I want to disabled all dates before endDate and vise versa.
how to disable dates using elemnt-ui.
>
This is an old question but I asked myself the same today. You can achieve this using the disabledDate picker option. Here's an example on how to disable all future dates:
<el-date-picker
:picker-options="datePickerOptions"
</el-date-picker>
Then in your data object:
data () {
return {
datePickerOptions: {
disabledDate (date) {
return date > new Date()
}
}
}
}
fist of all you should define picker options for your end date input.
The main problem is using this keyword inside the disabledDate method of picker options, so you should move exactly method outside the data definition to the methods part
So, complete code should looks something like this:
data () {
return {
task: {
start_at: new Date(),
end_at: new Date()
}
dueDatePickerOptions: {
disabledDate: this.disabledDueDate
}
}
},
methods: {
disabledDueDate (time) {
return time.getTime() < this.task.start_at
},
validateEndDate () {
if (this.task.start_at > this.task.due_at) {
this.task.due_at = this.task.start_at
}
}
}
And HTML part of this example should looks like:
<el-date-picker #input="validateEndDate" v-model="task.start_at" type="date"></el-date-picker>
<el-date-picker v-model="task.end_at" :picker-options="dueDatePickerOptions" type="date"></el-date-picker>
Notice:
validateEndDate method will be triggered after changing startDate and check if endDate before startDate then fix endDate to be equals.
If you want to get between, you can try it:
datePickerOptions: {
disabledDate: this.disabledDueDate
}
and your method:
methods: {
disabledDueDate(date) { // format Date!
return !(date >= this.start && date <= this.end)
},
}
I solved this by putting the picker options inside the computed property, and using the moment.js library to check if the date is in between two dates:
computed: {
inBetweenDatesPickerOptions() {
return {
disabledDate: (time) => {
return !moment(time.getTime()).isBetween(this.form.start_date, this.form.end_date);
}
}
}
}
And in the markup you can set the options by using the :picker-options prop:
<el-date-picker
v-model="form.in_between_date"
:picker-options="inBetweenDatesPickerOptions"
type="date">
</el-date-picker>
An easier solution would be limiting min/max values dynamically. I suggest this:
<input type="date" class="form-control" v-model="dateFrom" :max="dateTo">
<input type="date" class="form-control" v-model="dateTo" :min="dateFrom">
This would limit the date picker to proper date ranges.