A blog probably of interest only to nerds by John Morton.

11May2020

Adding Date Val­i­da­tion Log­ic when Cre­at­ing an Event in Craft CMS 3

I have a Craft CMS site with two Date/​Time fields. One field is called calStartTime and the oth­er is calEndTime.

The goal is to check that calEndTime does not hap­pen before the calStartTime. To do this, I have a cus­tom mod­ule. Head over to plug​in​fac​to​ry​.io to scaf­fold out a mod­ule. You could also do this in a plu­g­in, but a mod­ule is prob­a­bly easier. 

Lis­ten 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 val­i­da­tion works, but the author­ing expe­ri­ence is not ide­al with the out-of-the-box Date/​Time field. The Date/​Time field sets the default date shown upon the ini­tial click to the cur­rent date. That does­n’t make much sense for the sec­ond date field though since the date log­i­cal­ly should not be before the date sent for the start time. The Date/​Time field uses the jQuery datepick­er from the jQuery UI frame­work. The few lines of Javascript below will address the issue.

When the date por­tion (as opposed to the time por­tion) of the calStartTime field is clicked, it reports back the date select­ed and then changed the defaultDate for the calEndTime field (the date por­tion) to that cho­sen date. Updat­ing the defaultDate won’t have any effect when the edit page is used to alter an already exist­ing cal­en­dar 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 con­trol pan­el. You can do this through a cus­tom mod­ule or use Con­trol Pan­el JS from the Plu­g­in 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 );
});