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;
}
}
Related
I would like to prevent a new slot being created when already occupied. For example, if the dates selected overlap e.g. Slot one has 10am to 11am and potential added slot is 10:15 to 11:15, I want to block this as some of the time is already taken.
Currently, I am trying to use the dateEvent option in Vue but it still creates the slot. I wanted to get the current slot data but can't find a way of doing this and eventOverlap and slotEventOverlap seem to do nothing in this context.
Has anyone run into this problem before?
Code Example:
export default {
components: {
FullCalendar
},
mounted() {
console.log('Component mounted.')
},
data() {
return {
allEvents: [],
calendarOptions: {
plugins: [timeGridPlugin, dayGridPlugin, interactionPlugin],
initialView: 'timeGridDay',
selectable: true,
selectMirror: true,
allDaySlot: false,
slotDuration: "00:15:00",
slotMinTime: '09:00:00',
slotMaxTime: '19:00:00',
editable: false,
eventLimit: true,
eventOverlap: false,
slotEventOverlap: false,
dateClick: this.handleDateClick,
events: function (fetchInfo, successCallback, failureCallback) {
//...
},
}
}
},
methods: {
handleDateClick: function (arg) {
console.log(arg, arg.view.getCurrentData())
let startDateTime = new Date(arg.dateStr)
let endDateTime = new Date(arg.dateStr)
const calendar = this.$refs.fullCalendar.getApi()
var event = calendar.getEventById('my-event')
if (event) {
event.remove()
}
calendar.addEvent({
id: 'my-event',
title: 'Selected Slot',
start: startDateTime,
end: new Date(endDateTime.setHours(endDateTime.getHours() + 1))
})
calendar.unselect()
}
},
}
Currently iam trying to pass an array of events in my database as a simple parameter. Below i attach my backend callback, the query document and the pure javascript Full Calendar implementation. So i tried forEach but gives me error . If i pass directly the objects array anaylitically then all works fine, but my issue is that i cannot render events by providing the array variable as argument. I wont like use JSON feed feature because my api is not able to be configurated. Any suggestion welcomed, thank you in advance
calendar:35 Uncaught ReferenceError: eventsArray is not defined
at HTMLDocument.<anonymous>
Express Js Callback
exports.getcalendar=async function (req,res,next){
var bookdata={};
try{
bookdata=await booking.aggregate().match({resourceID:mongoose.Types.ObjectId(req.params.id)}).project({
'title':'$Project_title',
'start':'$date_started',
'end':'$date_finished',
'_id':0
})
}catch (error){
return next(error);
}
finally {
console.log(JSON.parse(JSON.stringify(bookdata)));
res.render('calendar',{databook:JSON.parse(JSON.stringify(bookdata))});
}
};
bookdata
[
{
title: 'prj',
start: '2021-04-08T20:25:00.000Z',
end: '2021-04-09T20:25:00.000Z'
},
{
title: 'Proej3',
start: '2021-04-12T00:58:00.000Z',
end: '2021-04-13T00:58:00.000Z'
},
{
title: 'May proj',
start: '2021-05-10T11:00:00.000Z',
end: '2021-05-11T11:00:00.000Z'
},
{
title: 'prj',
start: '2021-04-28T15:00:00.000Z',
end: '2021-04-28T18:00:00.000Z'
}
]
FullCalendar Constructor
script.
document.addEventListener('DOMContentLoaded', function (databook) {
var calendarEl = document.getElementById('calendar');
var initdate = new Date();
var calendar = new FullCalendar.Calendar(calendarEl, {
function(){
var eventsArray=[];
bookdata.forEach(function (element){
eventsArray.push({
title:element.title,
start:element.start,
end:element.end })
})
},
initialView: 'dayGridMonth',
timeZone:'Europe/Athens',
initialDate: initdate,
handleWindowResize:true,
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay'
},
eventTimeFormat:{
hour: 'numeric',
minute: '2-digit',
},
eventDisplay:'auto',
views:{
timeGrid:{
formatDateTime:'DD/MM/YYYY HH:mm'
}
},
events:eventsArray
});
calendar.addEvent()
calendar.render();
});
Don't create the eventsArray variable inside the calendar variable. You can initialize it right before the calendarEl is created for example
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>
data() {
return {
datePickerOptions: {
disabledDate(date) {
// console.log(form.installation_date); // undefined form
return date < this.form.ins_date ? this.form.ins_date : new Date();
},
},
}
This is saying form undefined i can understand can't initiaize form input inside data return how can i achieve this. disable other date if greater than first input date
please guide
As I said in my comment, you can't have a function returning something in your data so you have to shift your logic somewhere else. You can put that function in your methods:
data() {
return {
datePickerOptions: {
disabledDate: this.isDateDisabled
},
// rest of data
...
methods: {
isDateDisabled(date) {
return date < new Date(this.ruleForm.date1);
},
i need to create a Dojo widget that lets users specify date & time. i found a sample implementation attached to an entry in the Dojo bug tracker. It looks nice and mostly works, but when i submit the form, the value sent by the client is not the user-selected value but the value sent from the server.
What changes do i need to make to get the widget to submit the date & time value?
Sample usage is to render a JSP with basic HTML tags (form & input), then
dojo.addOnLoad a function which selects the basic elements by ID, adds dojoType
attribute, and dojo.parser.parse()-es the page.
Thanks in advance.
The widget is implemented in two files. The application uses Dojo 1.3.
File 1: DateTimeCombo.js
dojo.provide("dojox.form.DateTimeCombo");
dojo.require("dojox.form._DateTimeCombo");
dojo.require("dijit.form._DateTimeTextBox");
dojo.declare(
"dojox.form.DateTimeCombo",
dijit.form._DateTimeTextBox,
{
baseClass: "dojoxformDateTimeCombo dijitTextBox",
popupClass: "dojox.form._DateTimeCombo",
pickerPostOpen: "pickerPostOpen_fn",
_selector: 'date',
constructor: function (argv) {},
postMixInProperties: function()
{
dojo.mixin(this.constraints, {
/*
datePattern: 'MM/dd/yyyy HH:mm:ss',
timePattern: 'HH:mm:ss',
*/
datePattern: 'MM/dd/yyyy HH:mm',
timePattern: 'HH:mm',
clickableIncrement:'T00:15:00',
visibleIncrement:'T00:15:00',
visibleRange:'T01:00:00'
});
this.inherited(arguments);
},
_open: function ()
{
this.inherited(arguments);
if (this._picker!==null && (this.pickerPostOpen!==null && this.pickerPostOpen!==""))
{
if (this._picker.pickerPostOpen_fn!==null)
{
this._picker.pickerPostOpen_fn(this);
}
}
}
}
);
File 2: _DateTimeCombo.js
dojo.provide("dojox.form._DateTimeCombo");
dojo.require("dojo.date.stamp");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.require("dijit._Calendar");
dojo.require("dijit.form.TimeTextBox");
dojo.require("dijit.form.Button");
dojo.declare("dojox.form._DateTimeCombo",
[dijit._Widget, dijit._Templated],
{
// invoked only if time picker is empty
defaultTime: function () {
var res= new Date();
res.setHours(0,0,0);
return res;
},
// id of this table below is the same as this.id
templateString:
" <table class=\"dojoxDateTimeCombo\" waiRole=\"presentation\">\
<tr class=\"dojoxTDComboCalendarContainer\">\
<td>\
<center><input dojoAttachPoint=\"calendar\" dojoType=\"dijit._Calendar\"></input></center>\
</td>\
</tr>\
<tr class=\"dojoxTDComboTimeTextBoxContainer\">\
<td>\
<center><input dojoAttachPoint=\"timePicker\" dojoType=\"dijit.form.TimeTextBox\"></input></center>\
</td>\
</tr>\
<tr><td><center><button dojoAttachPoint=\"ctButton\" dojoType=\"dijit.form.Button\">Ok</button></center></td></tr>\
</table>\
",
widgetsInTemplate: true,
constructor: function(arg) {},
postMixInProperties: function() {
this.inherited(arguments);
},
postCreate: function() {
this.inherited(arguments);
this.connect(this.ctButton, "onClick", "_onValueSelected");
},
// initialize pickers to calendar value
pickerPostOpen_fn: function (parent_inst) {
var parent_value = parent_inst.attr('value');
if (parent_value !== null) {
this.setValue(parent_value);
}
},
// expects a valid date object
setValue: function(value) {
if (value!==null) {
this.calendar.attr('value', value);
this.timePicker.attr('value', value);
}
},
// return a Date constructed date in calendar & time in time picker.
getValue: function() {
var value = this.calendar.attr('value');
var result=value;
if (this.timePicker.value !== null) {
if ((this.timePicker.value instanceof Date) === true) {
result.setHours(this.timePicker.value.getHours(),
this.timePicker.value.getMinutes(),
this.timePicker.value.getSeconds());
return result;
}
} else {
var defTime=this.defaultTime();
result.setHours(defTime.getHours(),
defTime.getMinutes(),
defTime.getSeconds());
return result;
}
},
_onValueSelected: function() {
var value = this.getValue();
this.onValueSelected(value);
},
onValueSelected: function(value) {}
});
It sounds like you want to use getValue. The convention now is to use _getValueAttr and then call attr("value") but I think that started in Dojo 1.4 and this code would need to be ported to use those new patterns.
Noe that value should be a Javascript Date object which would best be sent to the server using dojo.date.stamp.toISOString()
This began to work fine after i added a "serialize" method to DateTimeCombo.js which builds exactly the output format i want.
This seems odd to me, since there is already a serialize implementation in _DateTimeTextBox.js that should output the value in the required ISO format.