Click here to Skip to main content
15,508,200 members
Articles / Web Development / HTML
Article
Posted 24 Feb 2014

Stats

708.5K views
3.2K downloads
408 bookmarked

HTML5 Event Calendar/Scheduler

Rate me:
Please Sign up or sign in to vote.
4.92/5 (135 votes)
4 Dec 2022Apache8 min read
Weekly HTML5 event calendar with CSS themes, drag and drop support, date navigator. PHP and ASP.NET Core REST API backends.
In this article, we will build a simple HTML5 event calendar web application. The client-side (HTML5/JavaScript) part is universal. We will use sample PHP and ASP.NET Core backends. This article will look at: changing the calendar date using a date picker (on the left side), drag and drop event creating, moving and resizing, changing the look in a single click using a CSS theme, PHP backend, and ASP.NET Core backend (REST API).

Image 1

In this article, we will build a simple HTML5/JavaScript event calendar web application. The client-side part is universal. We will use sample PHP and ASP.NET Core backends.

Features:

  • Weekly HTML5 event calendar/scheduler
  • Changing the calendar using a date navigator (on the left side)
  • Drag and drop event creating, moving and resizing
  • Changing the look in a single click using a CSS theme
  • PHP REST backend
  • ASP.NET Core REST backend (.NET 7, Entity Framework)

We will use the open-source DayPilot Lite for JavaScript [javascript.daypilot.org] to build the event calendar. DayPilot Lite for JavaScript is available under Apache License 2.0.

New Feature: Icons and Context Menu

Image 2

Since version 2022.4, the calendar component supports event context menu and icons.

Icons can be added using active areas. Active areas are a universal tool for adding elements to events - you can use them to add images, status icons, action buttons, and drag handles.

Example:

onBeforeEventRender: args => {
  args.data.areas = [
    {
      top: 5,
      right: 5,
      width: 16,
      height: 16,
      symbol: "icons/daypilot.svg#minichevron-down-4",
      fontColor: "#666",
      visibility: "Hover",
      action: "ContextMenu",
      style: "background-color: #f9f9f9; border: 1px solid #666; cursor:pointer; border-radius: 15px;"
    }
  ];
},
contextMenu: new DayPilot.Menu({
  items: [
    {
      text: "Edit...",
      onClick: args => {
        app.editEvent(args.source);
      }
    },
    {
      text: "Delete",
      onClick: args => {
        app.deleteEvent(args.source);
      }
    },
    {
      text: "-"
    },
    {
      text: "Duplicate",
      onClick: args => {
        app.duplicateEvent(args.source);
      }
    },
  ]
})

Step 1: Event Calendar JavaScript Library

Include daypilot-all.min.js. No other dependencies are required for the basic look (the default CSS theme is embedded).

HTML
<script src="js/daypilot/daypilot-all.min.js" type="text/javascript"></script> 

Step 2: Event Calendar Placeholder

Add a placeholder <div> to the HTML5 page:

HTML
<div id="dp"></div> 

Step 3: Initialize the Scheduler

Initialize the scheduler using Daypilot.Calendar class:

HTML
<script type="text/javascript">
  const dp = new DayPilot.Calendar("dp", {
    viewType: "Week"
  });
  dp.init();
</script>

These simple steps will render an empty scheduler:

Image 3

Step 4: Load Data

We will load the data to the event calendar using a simple HTTP call:

JavaScript
async function loadEvents() {
  const start = dp.visibleStart();
  const end = dp.visibleEnd();

  // in .NET, use "/api/CalendarEvents?start=${start}&end=${end)"
  const {data} = await DayPilot.Http.get(`backend_events.php?start=${start}&end=${end)`);
  dp.update({
    events: data
  });
}

Since version 2018.2.232, you can also use a built-in shortcut method to load events:

JavaScript
function loadEvents() {
  // in .NET, use "api/CalendarEvents"
  dp.events.load("backend_events.php"); 
}

You can detect the currently-visible date range using visibleStart() and visibleEnd() methods. The events.load() method adds the start and end to the URL query string automatically.

The backend_event.php endpoint returns the calendar event data in the following format:

JavaScript
[
  {
    "id":"1",
    "text":"Calendar Event 1",
    "start":"2023-02-25T10:30:00",
    "end":"2023-02-25T16:30:00"
  },
  {
    "id":"2",
    "text":"Calendar Event 2",
    "start":"2023-02-24T09:00:00",
    "end":"2023-02-24T14:30:00"
  },
  {
    "id":"3",
    "text":"Calendar Event 3",
    "start":"2023-02-27T12:00:00",
    "end":"2023-02-27T16:00:00"
  }
]

PHP backend (backend_events.php):

PHP
<?php
require_once '_db.php';
    
$stmt = $db->prepare('SELECT * FROM events WHERE NOT ((end <= :start) OR (start >= :end))');

$stmt->bindParam(':start', $_GET['start']);
$stmt->bindParam(':end', $_GET['end']);

$stmt->execute();
$result = $stmt->fetchAll();

class Event {}
$events = array();

foreach($result as $row) {
  $e = new Event();
  $e->id = $row['id'];
  $e->text = $row['name'];
  $e->start = $row['start'];
  $e->end = $row['end'];
  $events[] = $e;
}

echo json_encode($events);

?>

ASP.NET Core backend (CalendarEventsController.cs):

C#
// GET: api/CalendarEvents
[HttpGet]
public async Task<ActionResult<IEnumerable<CalendarEvent>>> 
       GetEvents([FromQuery] DateTime start, [FromQuery] DateTime end)
{
    return await _context.Events
        .Where(e => !((e.End <= start) || (e.Start >= end)))
        .ToListAsync();
} 

Read more about loading the calendar event data [doc.daypilot.org].

Step 5: Event Moving

Image 4

The drag and drop user actions (selecting a time range, event moving, event resizing) are enabled by default in the scheduler.

We just need to add custom handler to submit the changes to the server side using an AJAX call.

JavaScript event handler (for PHP):

JavaScript
const dp = new DayPilot.Calendar("dp", {
  // ...
  onEventMoved: async (args) => {
    const data = {
      id: args.e.id(),
      newStart: args.newStart,
      newEnd: args.newEnd,
    };
    await DayPilot.Http.post(`backend_move.php`, data);
    console.log("The calendar event was moved.");
  }
});

PHP backend (backend_move.php):

PHP
<?php

require_once '_db.php';

$json = file_get_contents('php://input');
$params = json_decode($json);

$insert = "UPDATE events SET start = :start, end = :end WHERE id = :id";

$stmt = $db->prepare($insert);

$stmt->bindParam(':start', $params->newStart);
$stmt->bindParam(':end', $params->newEnd);
$stmt->bindParam(':id', $params->id);

$stmt->execute();

class Result {}

$response = new Result();
$response->result = 'OK';
$response->message = 'Update was successful';

header('Content-Type: application/json');
echo json_encode($response);

JavaScript event handler (for ASP.NET Core):

JavaScript
const dp = new DayPilot.Calendar("dp", {
  // ...
  onEventMoved: async (args) => {
    const id = args.e.id();
    const data = {
        id: args.e.id(),
        start: args.newStart,
        end: args.newEnd,
        text: args.e.text()
    };
    await DayPilot.Http.put(`/api/CalendarEvents/${id}`, data);
    console.log("The calendar event was moved.");
  }
});

ASP.NET Core backend (CalendarEventsController.cs):

C#
// PUT: api/CalendarEvents/5
[HttpPut("{id}")]
public async Task<IActionResult> PutCalendarEvent(int id, CalendarEvent calendarEvent)
{
    if (id != calendarEvent.Id)
    {
        return BadRequest();
    }

    _context.Entry(calendarEvent).State = EntityState.Modified;

    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!CalendarEventExists(id))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }

    return NoContent();
} 

Read more about drag and drop event moving [doc.daypilot.org].

Step 6: Event Editing

Image 5

You can use DayPilot Modal dialog to edit the events details. DayPilot Modal is an open-source library for building modal forms from code (online Modal Dialog Builder application for visual modal dialog design is also available).

First, we add an onEventClick event handler that is fired when users click an existing event.

Our modal dialog will have just a single form field (text value called "Name"):

JavaScript
const form = [
  {name: "Name", id: "text"}
];

Now we can open the modal dialog using DayPilot.Modal.form() method. The second parameter specifies the source data object. The data object will be used to fill the initial values (the id value of the form item specifies the property/field of the data object).

The DayPilot.Modal.form() method returns a promise. That means we can use the await syntax to wait for the result and simplify the code:

JavaScript
const modal = await DayPilot.Modal.form(form, args.e.data);
if (modal.canceled) {
  return;
}

The result is available as modal.result object. It's a copy of the original object, with the updated values applied.

This is our onEventClick event handler:

JavaScript
const dp = new DayPilot.Calendar("dp", {
  // ...
  onEventClick: async (args) => {
    const form = [
      {name: "Name", id: "text"}
    ];

    const modal = await DayPilot.Modal.form(form, args.e.data);
    if (modal.canceled) {
      return;
    }

    // PHP

    const data = {
      id: args.e.id(),
      text: modal.result.text
    };
    await DayPilot.Http.post(`backend_update.php`, data);
    
    // .NET 7
    /*

    const id = args.e.id();
    const data = {
        id: args.e.id(),
        start: args.e.start(),
        end: args.e.end(),
        text: modal.result.text
    };
    await DayPilot.Http.put(`/api/CalendarEvents/${id}`, data);

    */

    dp.events.update({
      ...args.e.data,
      text: modal.result.text
    });
    console.log("The calendar event was updated.");

  }
});

PHP backend (backend_update.php)

PHP
<?php
require_once '_db.php';

$json = file_get_contents('php://input');
$params = json_decode($json);

$insert = "UPDATE events SET name = :text WHERE id = :id";

$stmt = $db->prepare($insert);

$stmt->bindParam(':text', $params->text);

$stmt->execute();

class Result {}

$response = new Result();
$response->result = 'OK';
$response->message = 'Update successful';

header('Content-Type: application/json');
echo json_encode($response);

Step 7: Apply the CSS Theme

HTML5 Event Calendar - CSS Theme

If you want to use a custom CSS theme, you need to include the stylesheet:

HTML
<link type="text/css" rel="stylesheet" href="themes/calendar_transparent.css" /> 

And set the theme property during initialization:

HTML
<script type="text/javascript">
  const dp = new DayPilot.Calendar("dp", {
    viewType: "Week",
    theme: "calendar_transparent"
  });
  dp.init();
</script> 

You can choose one of the included CSS themes or you can create your own using the online CSS theme designer.

Scheduler CSS Themes

DayPilot Lite for JavaScript comes with several pre-built CSS themes.

You can create your own theme using the online CSS theme designer [themes.daypilot.org].

Default CSS Theme

Image 7

Green CSS Theme

Image 8

Traditional CSS Theme

Image 9

Transparent CSS Theme

Image 10

White CSS Theme

Image 11

Monthly Event Calendar

Image 12

DayPilot also includes a monthly event calendar view. The API of the monthly view control uses the same design as the daily/weekly calendar:

HTML
<div id="dp"></div>

<script type="text/javascript">
  const dp = new DayPilot.Month("dp");
  dp.startDate = "2023-01-01";
  dp.init();
</script>

Event Calendar Localization

Image 13

You can switch the event calendar locale easily using .locale property:

HTML
<script type="text/javascript">
  const dp = new DayPilot.Calendar("dp");
  dp.locale = "de-de";
  dp.init();
</script>  

The calendar includes built-in support for many following locales [api.daypilot.org].

You can also create and register your own locale:

JavaScript
DayPilot.Locale.register(
  new DayPilot.Locale('en-us', 
  {
    'dayNames':['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
    'dayNamesShort':['Su','Mo','Tu','We','Th','Fr','Sa'],
    'monthNames':['January','February','March','April','May',
                  'June','July','August','September','October','November','December'],
    'monthNamesShort':['Jan','Feb','Mar','Apr','May','Jun',
                       'Jul','Aug','Sep','Oct','Nov','Dec'],
    'timePattern':'h:mm tt',
    'datePattern':'M/d/yyyy',
    'dateTimePattern':'M/d/yyyy h:mm tt',
    'timeFormat':'Clock12Hours',
    'weekStarts':0
  }
)); 

Changing the Scheduler Date using a Date Picker

Image 14

You can use the DayPilot.Navigator date picker control (on the left side in the screenshot above) to change the scheduler dates (the visible week):

HTML
<div id="nav"></div>

<script type="text/javascript">
  const datePicker = new DayPilot.Navigator("nav", {
    showMonths: 3,
    skipMonths: 3,
    selectMode: "Week",
    onTimeRangeSelected: args => {
      dp.update({startDate: args.day});
      app.loadEvents();
    }
  });
  datePicker.init();
</script>

Duration Bar

HTML5 event calendar with duration bar support

Version 1.1 of the DayPilot Lite HTML5 event calendar supports a duration bar (an indicator of real calendar event duration on the left side of the event). It is enabled by default and you can style it using the CSS theme.

Event Customization (HTML, CSS)

HTML5 Event Calendar Customization

Since version 1.3 SP3, DayPilot Lite supports event customization using onBeforeEventRender event handler:

HTML
<div id="dp"></div>

<script type="text/javascript">

    const dp = new DayPilot.Calendar("dp");

    // view
    dp.startDate = "2016-06-06";
    dp.viewType = "Week";
    dp.durationBarVisible = false;

    dp.events.list = [
        {
            "start": "2016-06-07T10:00:00",
            "end": "2016-06-07T13:00:00",
            "id": "29b7a553-d44f-8f2c-11e1-a7d5f62eb123",
            "text": "Event 3",
            "backColor": "#B6D7A8",
            "borderColor": "#6AA84F"
        },
        {
            "start": "2016-06-07T14:00:00",
            "end": "2016-06-07T17:00:00",
            "id": "ff968cfb-eba1-8dc1-7396-7f0d4f465c8a",
            "text": "Event 4",
            "backColor": "#EA9999",
            "borderColor": "#CC0000",
            "tags": {
                "type": "important"
            }
        }
    ];

    dp.onBeforeEventRender = args => {
        if (args.data.tags && args.data.tags.type === "important"){
            args.data.html = "<b>Important Event</b><br>" + args.data.text;
            args.data.fontColor = "#fff";
            args.data.backColor = "#E06666";
        }
    };

    dp.init();


</script>

You can use it to customize the following properties:

  • backColor
  • barBackColor
  • barColor
  • barHidden
  • borderColor
  • cssClass
  • fontColor
  • html
  • toolTip

Demo:

Monthly Calendar Event Customization

Image 17

Event customization support was added to the monthly calendar control in DayPilot Lite for JavaScript 1.3 SP4.

DayPilot Month supports customization of the following event properties:

  • backColor
  • borderColor
  • cssClass
  • fontColor
  • html
  • toolTip

Demo:

Example:

HTML
<div id="dp"></div>

<script type="text/javascript">
    const dp = new DayPilot.Month("dp");

    // ...
    
    dp.events.list = [
        {
            "start": "2021-03-03T00:00:00",
            "end": "2021-03-03T12:00:00",
            "id": "5a8376d2-8e3d-9739-d5d9-c1fba6ec02f9",
            "text": "Event 3"
        },
        {
            "start": "2021-02-25T00:00:00",
            "end": "2021-02-27T12:00:00",
            "id": "1fa34626-113a-ccb7-6a38-308e6cbe571e",
            "text": "Event 4",
            "tags": {
                "type": "important"
            }
        },
        // ...
    ];

    dp.onBeforeEventRender = args => {
        var type = args.data.tags && args.data.tags.type;
        switch (type) {
            case "important":
                args.data.fontColor = "#fff";
                args.data.backColor = "#E06666";
                args.data.borderColor = "#E06666";
                break;
            // ...
        }
    };

    dp.init();

</script>

Support for Angular, React, and Vue

Version 2022.1 of DayPilot Lite includes support for Angular, React, and Vue frameworks. See the following tutorials for a quick introduction and a sample project download:

Resource Calendar

Image 18

Since version 2022.2, DayPilot Lite includes a resource calendar view which displays resources as columns.

This view lets you schedule events or make reservations for multiple resources and show them side-by-side.

Quick example:

JavaScript
const calendar = new DayPilot.Calendar("calendar", {
  viewType: "Resources",
  columns: [
    { name: "Room 1", id: "R1" },
    { name: "Room 2", id: "R2" },
    { name: "Room 3", id: "R3" },
    { name: "Room 4", id: "R4" },
  ]
});
calendar.init();

Read more in the resource calendar tutorials for JavaScript, Angular, React and Vue.

See Also

History

License

This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0


Written By
Czech Republic Czech Republic
My open-source event calendar/scheduling web UI components:

DayPilot for JavaScript, Angular, React and Vue

Comments and Discussions

 
Questionnice proyect Pin
Member 1409010012-Apr-22 5:59
Member 1409010012-Apr-22 5:59 
AnswerRe: nice proyect Pin
Dan Letecky12-Apr-22 6:21
Dan Letecky12-Apr-22 6:21 
QuestionCould u use XML 4 persistence ? Pin
NG_AU11-Apr-22 21:50
NG_AU11-Apr-22 21:50 
AnswerRe: Could u use XML 4 persistence ? Pin
Dan Letecky12-Apr-22 6:21
Dan Letecky12-Apr-22 6:21 
Questionintegrar con mysql Pin
JHON EDWARD VASQUEZ21-Nov-21 3:14
professionalJHON EDWARD VASQUEZ21-Nov-21 3:14 
QuestionMessage Closed Pin
12-Sep-21 18:05
acmatrix12-Sep-21 18:05 
QuestionCan be configured to have more than one resource? Pin
Toutsaint24-Jul-19 13:36
Toutsaint24-Jul-19 13:36 
QuestionColliding events Pin
Member 1447118426-May-19 10:24
Member 1447118426-May-19 10:24 
QuestionRecurring events? RRULE? Pin
21Junipers19-Jun-18 13:06
21Junipers19-Jun-18 13:06 
QuestionIs it free and can use commercial product Pin
Mou_kol27-Feb-18 21:54
Mou_kol27-Feb-18 21:54 
AnswerRe: Is it free and can use commercial product Pin
Dan Letecky18-Jun-18 5:45
Dan Letecky18-Jun-18 5:45 
QuestionOverlapping Events? Pin
Connie DeCinko15-Dec-16 5:28
Connie DeCinko15-Dec-16 5:28 
QuestionOverlapping Events? Pin
Connie DeCinko15-Dec-16 5:28
Connie DeCinko15-Dec-16 5:28 
Questioncanendar does not show if I change index.cshtml Pin
petercli17-Sep-16 5:53
petercli17-Sep-16 5:53 
GeneralCalendar/Scheduler event coding system Pin
Member 1270290925-Aug-16 1:25
Member 1270290925-Aug-16 1:25 
QuestionJuste thanks for sharing Pin
JulienduWeb9-Jun-16 4:12
JulienduWeb9-Jun-16 4:12 
AnswerRe: Juste thanks for sharing Pin
Dan Letecky9-Jun-16 22:17
Dan Letecky9-Jun-16 22:17 
QuestionRead only mode available Pin
Member 412512527-Apr-16 21:22
Member 412512527-Apr-16 21:22 
AnswerRe: Read only mode available Pin
Dan Letecky29-Apr-16 5:13
Dan Letecky29-Apr-16 5:13 
GeneralMy vote of 5 Pin
csharpbd26-Apr-16 11:39
professionalcsharpbd26-Apr-16 11:39 
GeneralRe: My vote of 5 Pin
Dan Letecky26-Apr-16 11:46
Dan Letecky26-Apr-16 11:46 
GeneralMy vote of 5 Pin
JH645-Nov-15 3:21
JH645-Nov-15 3:21 
GeneralRe: My vote of 5 Pin
Dan Letecky5-Nov-15 3:31
Dan Letecky5-Nov-15 3:31 
QuestionMy Vote of 5 Pin
Robert Marck4-Nov-15 5:08
Robert Marck4-Nov-15 5:08 
AnswerRe: My Vote of 5 Pin
Dan Letecky4-Nov-15 10:27
Dan Letecky4-Nov-15 10:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.