Adding Date Validation Logic when Creating an Event in Craft CMS 3
I have a Craft CMS site with two Date/Time fields. One field is called calStartTime
and the other is calEndTime
.
The goal is to check that calEndTime
does not happen before the calStartTime
. To do this, I have a custom module. Head over to pluginfactory.io to scaffold out a module. You could also do this in a plugin, but a module is probably easier.
Listen for the Entry::EVENT_BEFORE_SAVE
event and then make sure the dates are valid.
Event::on(Entry::class, Entry::EVENT_BEFORE_SAVE, function (ModelEvent $calendarEntryEvent) {
$entry = $calendarEntryEvent->sender;
// Is there a Start Date set?
if (isset($entry->getFieldValues()['calStartTime'])) {
// Yes, there is a start date, but is there an end date set?
if (isset($entry->getFieldValues()['calEndTime'])) {
// Yes, we have an end date also, now let's confirm that
// the start date happens before the end date
$startTime = $entry->getFieldValues()['calStartTime']->getTimestamp();
$endTime = $entry->getFieldValues()['calEndTime']->getTimestamp();
// is start before end?
$validStartAndEndDate = $startTime <= $endTime;
// Reference for adding custom errors to the page:
// https://craftcms.stackexchange.com/questions/33827/add-new-error-to-macro-errorlist-user-registration/33832#33832
if(!$validStartAndEndDate) {
$entry->addError('calEndTime', 'If you set an ending time, it must be after the start time.');
$calendarEntryEvent->isValid = false;
}
}
}
});
Adding AX help with Javascript
The validation works, but the authoring experience is not ideal with the out-of-the-box Date/Time field. The Date/Time field sets the default date shown upon the initial click to the current date. That doesn’t make much sense for the second date field though since the date logically should not be before the date sent for the start time. The Date/Time field uses the jQuery datepicker from the jQuery UI framework. The few lines of Javascript below will address the issue.
When the date portion (as opposed to the time portion) of the calStartTime
field is clicked, it reports back the date selected and then changed the defaultDate
for the calEndTime
field (the date portion) to that chosen date. Updating the defaultDate
won’t have any effect when the edit page is used to alter an already existing calendar event because the defaultDate
field is only used when the field has no value.
Here’s the small bit of Javascript to add to your control panel. You can do this through a custom module or use Control Panel JS from the Plugin Store.
let startDate = $("input[name='fields[calStartTime][date]']");
let endDate = $("input[name='fields[calEndTime][date]']");
startDate.on('change', function(e) {
endDate.datepicker( "option", "defaultDate", e.currentTarget.value );
});