---
title: "JQuery Timeline Block Past Event Creation Example | Mobiscroll"
component: "Timeline"
framework: "jQuery"
library_version: "6.1.5"
url: "https://demo.mobiscroll.com/jquery/timeline/disallow-past-event-creation"
---

# Block Past Event Creation - jQuery Timeline demo

Keep past dates read-only on a JQuery resource timeline — block creation, moving, and resizing, and show a toast for blocked actions.

- [Live demo](https://demo.mobiscroll.com/jquery/timeline/disallow-past-event-creation)
- [View code on GitHub](https://github.com/acidb/mobiscroll-demos-jquery/tree/main/src/demos/eventcalendar/timeline/disallow-past-event-creation)
- This demo in other frameworks: [JavaScript](https://demo.mobiscroll.com/javascript/timeline/disallow-past-event-creation.md), [Angular](https://demo.mobiscroll.com/angular/timeline/disallow-past-event-creation.md), [React](https://demo.mobiscroll.com/react/timeline/disallow-past-event-creation.md), [Vue](https://demo.mobiscroll.com/vue/timeline/disallow-past-event-creation.md)

## Description

Sometimes we don't want users to be able to create events in the past or to alter past events. This might be role based in some cases or applied in general to the calendar.

To disable past event creation and manipulation, a couple of things need to be handled:

- **Invalidate dates that are before today** - this takes care of validating event drop and event creation on past dates
- **Mark past events as fixed** - to do this, set the `editable` property of the event object to `false` for the events that should remain fixed
- **Handle past occurrences of recurring events** - recurring events are loaded as a single event and the occurrences are generated by the timeline. Moving the past occurrences need to be handled in the [`onEventUpdate`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onEventUpdate) and [`onEventCreate`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onEventCreate) lifecycle events
- **Give feedback to the user** - optionally, a toast can be displayed to give feedback to the user why an event cannot be dropped, moved and created in the past. For this we can use the [`onEventCreateFailed`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onEventCreateFailed) and [`onEventUpdateFailed`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onEventUpdateFailed) lifecycle events

## What this demo shows

- A desktop monthly resource timeline that blocks event creation and event editing in the past.
- **Header navigation** The month and year label opens date navigation, the previous and next arrows move between months, and the Today button returns to the current date.
- **Month view** Days are arranged horizontally across the selected month, with the current date highlighted.
- **Past dates** Dates before today are disabled and rendered with a gray background.
- **Disabled past days** Disabled past dates block event creation, drag-to-move, and drag-to-resize interactions.
- **Past events** Events on past dates remain visible, but they cannot be moved, resized, or repositioned.
- **Failed past updates** When creating or moving an event is blocked by a past date, a toast appears at the bottom center with feedback explaining why the action was not allowed.
- **Resources** Multiple resources are listed as separate timeline rows on the left.
- **Event cards** Events appear as colored cards with a colored stripe on the left, a bold event title, and the exact start and end time below the title.
- **Date positioning** Events are positioned by their assigned resource and exact date range.
- **Event interaction** Editable events highlight on hover and show drag and resize handles for moving or changing duration.
- **Event selection** Clicking an event selects and highlights it.
- **Event creation** New events can be created by double-clicking the timeline or by clicking and dragging across a valid time range.
- **Scrolling** The timeline supports horizontal and vertical scrolling for navigating through days and resources.

## Best for

- **Booking systems** Preventing users from creating appointments in dates or times that have already passed.
- **Resource scheduling** Keeping completed or historical assignments visible while blocking accidental edits.
- **Workforce planning** Protecting past shifts, jobs, or allocations after the scheduled date has passed.
- **Service operations** Allowing teams to review past work without changing records that should remain fixed.
- **Audit-sensitive calendars** Separating future scheduling changes from historical event data that should not be moved or resized.

## API used in this demo

- [`theme`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-theme) - option
- [`themeVariant`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-themeVariant) - option
- [`view`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-view) - option
- [`invalid`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-invalid) - option
- [`resources`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-resources) - option
- [`clickToCreate`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-clickToCreate) - option
- [`dragToCreate`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-dragToCreate) - option
- [`dragToMove`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-dragToMove) - option
- [`dragToResize`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-dragToResize) - option
- [`onEventCreateFailed`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onEventCreateFailed) - event
- [`onEventUpdateFailed`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onEventUpdateFailed) - event
- [`onEventCreate`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onEventCreate) - event
- [`updateEvent`](https://mobiscroll.com/docs/jquery/eventcalendar/api#method-updateEvent) - method
- [`onEventUpdate`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onEventUpdate) - event
- [`setEvents`](https://mobiscroll.com/docs/jquery/eventcalendar/api#method-setEvents) - method

## Code

### JS

```js
mobiscroll.setOptions({
  theme: 'ios',
  themeVariant: 'light'
});

$(function () {
  var now = new Date(new Date().setMinutes(59));
  var today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
  var yesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);

  var inst = $('#demo-disallow-past-event-creation')
    .mobiscroll()
    .eventcalendar({
      view: { timeline: { type: 'month' } },
      invalid: [{ recurring: { repeat: 'daily', until: yesterday } }, { start: today, end: now }],
      resources: [
        { id: 1, name: 'Resource A', color: '#e20000' },
        { id: 2, name: 'Resource B', color: '#76e083' },
        { id: 3, name: 'Resource C', color: '#4981d6' },
        { id: 4, name: 'Resource D', color: '#e25dd2' },
        { id: 5, name: 'Resource E', color: '#1dab2f' },
        { id: 6, name: 'Resource F', color: '#d6d145' },
      ],
      clickToCreate: true,
      dragToCreate: true,
      dragToMove: true,
      dragToResize: true,
      onEventCreateFailed: function (args) {
        if (!args.originEvent) {
          mobiscroll.toast({
            message: "Can't create event in the past",
          });
        }
      },
      onEventUpdateFailed: function (args) {
        if (!args.oldEventOccurrence) {
          mobiscroll.toast({
            message: "Can't move event in the past",
          });
        }
      },
      onEventCreate: function (args) {
        var oldEvent = args.originEvent;
        var start = oldEvent && oldEvent.start ? oldEvent.start : null;

        // Handle recurring events
        if (start && start < today) {
          inst.updateEvent(oldEvent);
          mobiscroll.toast({
            message: "Can't move past event",
          });
          return false;
        }
      },
      onEventUpdate: function (args) {
        var oldEvent = args.oldEvent;
        var start = oldEvent && oldEvent.start ? oldEvent.start : null;
        var oldEventOccurrence = args.oldEventOccurrence;
        var occurrenceStart = oldEventOccurrence && oldEventOccurrence.start ? oldEventOccurrence.start : null;

        // Handle recurring events
        if ((start && start < today) || (occurrenceStart && occurrenceStart < today)) {
          inst.updateEvent(oldEvent);
          return false;
        }
      },
    })
    .mobiscroll('getInst');

  $.getJSON(
    'https://trial.mobiscroll.com/multiday-events/?callback=?',
    function (events) {
      for (var i = 0; i < events.length; ++i) {
        var event = events[i];
        // Convert dates to date objects
        event.start = event.start ? new Date(event.start) : event.start;
        event.end = event.end ? new Date(event.end) : event.end;
        // Mark past events as fixed by setting the event.editable property to false
        event.editable = event.start && today < event.start;
      }
      inst.setEvents(events);
    },
    'jsonp',
  );
});
```

### HTML

```html
<div id="demo-disallow-past-event-creation" class="md-disallow-past-event-creation"></div>
```

### CSS

```css
.md-disallow-past-event-creation .mbsc-readonly-event {
    opacity: .6;
}
```

## Implementation notes

- Use `timeline: { type: 'month' }` - a monthly view.
- Define 6 resources (A-F) with `id`, `name`, and `color`.
- Enable all four interaction modes: `clickToCreate: true`, `dragToCreate: true`, `dragToMove: true`, `dragToResize: true`.
- Compute three date references at module level: `now = new Date(new Date().setMinutes(59))` (current time with minutes snapped to 59), `today = new Date(now.getFullYear(), now.getMonth(), now.getDate())` (midnight today), `yesterday` (midnight yesterday).
- Pass an `invalid` array with two entries to block past dates: `{ recurring: { repeat: 'daily', until: yesterday } }` (blocks all days before today) and `{ start: today, end: now }` (blocks the already-elapsed portion of today). Together these prevent creating or dropping events at any time in the past.
- Load events asynchronously from `https://trial.mobiscroll.com/multiday-events/` via JSONP. After loading: convert `event.start` and `event.end` string values to `Date` objects, then set `event.editable = event.start && today < event.start` - only future events are editable; past events get `editable: false`, which locks them against drag/resize/delete.
- Apply CSS: `.md-disallow-past-event-creation .mbsc-readonly-event { opacity: 0.6 }` - Mobiscroll automatically adds the `mbsc-readonly-event` class to events with `editable: false`, giving past events a faded appearance.
- **`onEventCreateFailed`** - fires when a new event creation is blocked by `invalid`. Only show the toast ("Can't create event in the past") when `args.originEvent` is absent - this guards against false positives when a recurring event's past occurrence triggers the handler.
- **`onEventUpdateFailed`** - fires when a move or resize is blocked by `invalid`. Only show the toast ("Can't move event in the past") when `args.oldEventOccurrence` is absent - this avoids duplicate toasts for recurring occurrence failures.
- **`onEventCreate`** - handles the recurring event edge case: a past occurrence of a recurring event can be dragged and will trigger `onEventCreate` (not `onEventUpdateFailed`) because the occurrence is treated as a new event. Read `args.originEvent.start`; if it is before `today`, show a toast ("Can't move past event") and `return false` to cancel.
- **`onEventUpdate`** - handles recurring events being moved from the past. Check `args.oldEvent.start < today` (master event started in the past) OR `args.oldEventOccurrence.start < today` (a specific past occurrence is being moved). If either is true, `return false` to cancel.

## Run it in your project

1. If not signed up yet, or don't own a license, you can [start a free trial](https://mobiscroll.com/starttrial).

2. Clone the repository:

   ```
   git clone https://github.com/acidb/mobiscroll-demos-jquery.git
   ```

3. If not installed yet, install the Mobiscroll CLI from NPM:

   ```
   npm install -g @mobiscroll/cli
   ```

4. Config Mobiscroll - open a terminal window in the root directory and run:

   ```
   mobiscroll config jquery
   ```

5. Install dependencies - open a terminal window in the root directory and run:

   ```
   npm install
   ```

6. Run the project:

   ```
   npm run dev
   ```

On a trial, add `--trial` to the config command: `mobiscroll config jquery --trial`.

Running a demo locally requires a Mobiscroll trial or a license; setup is per framework at https://mobiscroll.com/docs/jquery/getting-started/installation

## Related demos

- Previous: [CRUD Events](https://demo.mobiscroll.com/jquery/timeline/create-read-update-delete-CRUD.md) - Add, edit, move, resize, and delete events on a JQuery Timeline — drag or double-click to create; set color, dates and all-day options in a dialog.
- Next: [Multi-Select & Bulk Event Actions](https://demo.mobiscroll.com/jquery/timeline/event-bulk-actions-edit-delete-update.md) - Select multiple events on a JQuery Timeline by keyboard shortcut or button, then apply bulk delete or update — a side panel tracks the selection.
