Features

This tutorial uses the event calendarmonthly calendar, and date navigator components from DayPilot Pro package to build a simple HTML5/JavaScript calendar application with integrated day, week, and month views.

  • Daily, weekly and monthly event calendars that provide different views of the same data
  • Date navigator for changing the current date
  • All calendar components support drag and drop event creating, moving and resizing
  • Simplified calendar data loading using the built-in events.load() method
  • PHP backend that provides access to the database using REST API
  • MySQL and SQLite database

License

Licensed for testing and evaluation purposes. Please see the license agreement included in the sample project. You can use the source code of the tutorial if you are a licensed user of DayPilot Pro for JavaScript. Buy a license.

HTML5/JavaScript Daily Calendar

html5-javascript-daily-event-calendar-php-mysql.png

The daily calendar view is built using DayPilot.Calendar class with viewType set to "Day". This view displays a calendar for 24 hours of a single day. By default, the viewport is limited to business hours (predefined as 9 a.m. to 6 p.m.). Users can access the remaining hours using a vertical scrollbar.

The daily calendar will be rendered in a placeholder <div> which is marked with id="dpDay". The DayPilot.Calendar instance is stored as day JavaScript variable.

HTML5

<div id="dpDay"></div>

JavaScript

<script type="text/javascript">

  var day = new DayPilot.Calendar("dpDay");
  day.viewType = "Day";
  day.init();

</script>

HTML5/JavaScript Weekly Calendar

html5-javascript-weekly-event-calendar-php-mysql.png

The weekly calendar is built using DayPilot.Calendar class with viewType set to "Week". You can see that the weekly calendar is built using the same DayPilot.Calendar component. However, this time it uses a different placeholder div (id="dpWeek") and it creates a different instance (stored as week variable). This allows us to work with both instances at once. When switching between view, we will simply hide or show the instances as needed. This way, we will avoid the overhead of creating and destroying the calendar instances when switching views.

As you can see, the configuration is very simple - the only property we define is the viewType.

HTML5

<div id="dpWeek"></div>

JavaScript

<script type="text/javascript">

  var week = new DayPilot.Calendar("dpWeek");
  week.viewType = "Week";
  week.init();

</script>

HTML5/JavaScript Monthly Calendar

html5-javascript-monthly-event-calendar-php-mysql.png

The monthly calendar view is built using DayPilot.Month class. This time it's a different class that represents the month view which uses a different layout. As in the previous cases, we use a special placeholder (id="dpMonth") and store the instance as month variable.

HTML5

<div id="dpMonth"></div>

JavaScript

<script type="text/javascript">

  var month = new DayPilot.Month("dpMonth");
  month.init();

</script>

Loading Calendar Event Data

html5-javascript-event-calendar-day-week-month-loading-data.png

The day/week (DayPilot.Calendar) and month (DayPilot.Month) calendar components support events.load() shortcut method for loading events

dp.events.load("backend_events.php");

You can use this method to load events from a remote data source. It expects a JSON array with calendar event data as a response.

It automatically adds the start and end of the current view as query string parameters to the specified URL. You can use these parameters to limit the SQL query on the server side.

PHP ("backend_events.php")

<?php
require_once '_db.php';

// .events.load() passes start and end as query string parameters by default
$start = $_GET["start"];
$end = $_GET["end"];
    
$stmt = $db->prepare('SELECT * FROM events WHERE NOT ((end <= :start) OR (start >= :end))');

$stmt->bindParam(':start', $start);
$stmt->bindParam(':end', $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;
}

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

The sample MySQL database uses a simple schema with just one table called events:

CREATE TABLE `events` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`name` TEXT NULL,
	`start` DATETIME NOT NULL,
	`end` DATETIME NOT NULL,
	PRIMARY KEY (`id`)
);

How Does events.load() Work

This dp.events.load() method is a shortcut method that updates the calendar data using an AJAX call

The calendar event data is stored in dp.events.list array. Example:

dp.events.list = [
  {
    "start": "2019-09-16T10:30:00",
    "end": "2019-09-16T12:00:00",
    "id": "2",
    "text": "Meeting"
  }
];

You can load the data during the initial page load:

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

<script type="text/javascript">

  var dp = new DayPilot.Calendar("dp");
  dp.viewType = "Week";
  dp.events.list = [
   {
    "start": "2019-09-16T10:30:00",
    "end": "2019-09-16T12:00:00",
    "id": "2",
    "text": "Meeting"
   }
  ];
  dp.init();

</script>

You can also load the data using a separate AJAX call (this example uses jQuery $.post):

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

<script type="text/javascript">

  var dp = new DayPilot.Calendar("dp");
  dp.viewType = "Week";
  dp.init();

  $.get(
    "backend_events.php?start=" + dp.visibleStart() + "&end=" + dp.visibleEnd(),
    function(data) {
      dp.events.list = data;
      dp.update();
    }
   );

</script>

The jQuery $.get call can be replaced with dp.events.load():

  1. It sends a GET HTTP request that loads the calendar data in JSON format. It sends the visibleStart() date as "start" query string parameter and visibleEnd() date as "end" query string parameter.
  2. It assigns the data to dp.events.list
  3. It updates the calendar using dp.update()
  4. You can configure the HTTP method ("POST" | "GET") using "eventsLoadMethod" property

JavaScript

dp.events.load("backend_events.php");

Calendar Drag and Drop Support

We will add four events handlers:

  • onEventMoved
  • onEventResized
  • onTimeRangeSelected
  • onEventClick

The syntax of all event handlers is the same in the DayPilot.Calendar and DayPilot.Month. We can use a help method that will add the event handlers to all views.

JavaScript

function addEventHandlers(dp) {
  dp.onEventMoved = function (args) {
      $.post("backend_move.php", 
              {
                  id: args.e.id(),
                  newStart: args.newStart.toString(),
                  newEnd: args.newEnd.toString()
              }, 
              function() {
                  console.log("Moved.");
              });
  };

  dp.onEventResized = function (args) {
      $.post("backend_resize.php", 
              {
                  id: args.e.id(),
                  newStart: args.newStart.toString(),
                  newEnd: args.newEnd.toString()
              }, 
              function() {
                  console.log("Resized.");
              });
  };

  // event creating
  dp.onTimeRangeSelected = function (args) {
      var name = prompt("New event name:", "Event");
      dp.clearSelection();
      if (!name) return;
      var e = new DayPilot.Event({
          start: args.start,
          end: args.end,
          id: DayPilot.guid(),
          resource: args.resource,
          text: name
      });
      dp.events.add(e);

      $.post("backend_create.php", 
              {
                  start: args.start.toString(),
                  end: args.end.toString(),
                  name: name
              }, 
              function() {
                  console.log("Created.");
              });

  };

  dp.onEventClick = function(args) {
      alert("clicked: " + args.e.id());
  };
}

Date Navigator

html5-javascript-date-picket-calendar-navigator.png

The last missing piece of the UI is a date navigator (date picker) that will let the users switch the visible date.

HTML5

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

JavaScript

<script type="text/javascript">
  var nav = new DayPilot.Navigator("nav");
  nav.showMonths = 3;
  nav.skipMonths = 3;
  nav.init();
</script>

Switching the Day/Week/Month Views

html5-javascript-event-calendar-day-week-month-php-mysql-switching.png

Now it's time to assemble all components and views into a complex calendar view. We have the following components:

  • buttons for switching the current view (simple <a> links with "Day", "Week", and "Month" text)
  • day, week, and month views (DayPilot.Calendar, DayPilot.Month objects)
  • navigator (DayPilot.Navigator)

We will use the DayPilot.Switcher helper to bind all calendar components together.

HTML5

<div style="float:left; width: 220px;">
    <div id="nav"></div>
</div>
<div style="margin-left: 220px;">
    <div class="space buttons">
        <a id="buttonDay" href="#">Day</a>
        <a id="buttonWeek" href="#">Week</a>
        <a id="buttonMonth" href="#">Month</a>
    </div>
    <div id="dpDay"></div>
    <div id="dpWeek"></div>
    <div id="dpMonth"></div>
</div>

JavaScript

<script type="text/javascript">

  // initialize the date navigator
  var nav = new DayPilot.Navigator("nav");
  nav.showMonths = 3;
  nav.skipMonths = 3;
  nav.init();
                 
  // initialize the day view
  var day = new DayPilot.Calendar("dpDay");
  day.viewType = "Day";
  addEventHandlers(day);
  day.init();

  // initialize the week view
  var week = new DayPilot.Calendar("dpWeek");
  week.viewType = "Week";
  addEventHandlers(week);
  week.init();

  // initialize the month view
  var month = new DayPilot.Month("dpMonth");
  addEventHandlers(month);
  month.init();

  // ...

  var switcher = new DayPilot.Switcher({
      triggers: [
          {id: "buttonDay", view: day },    // link buttonDay to day view
          {id: "buttonWeek", view: week},   // link buttonWeek to week view
          {id: "buttonMonth", view: month}  // link buttonMonth to month view
      ],
      navigator: nav,
      selectedClass: "selected-button",  // add this class to the selected trigger
      onChanged: function(args) {
          switcher.events.load("backend_events.php");   // action to be performed when the view or date changes - reload the events for the current view
      }
  });
  
  switcher.select("buttonWeek");

</script>

History

  • September 19, 2019: Upgraded to DayPilot Pro for JavaScript 2019.3.4012. Support for MySQL. Using DayPilot.Modal.prompt().
  • June 27, 2017: Upgraded to DayPilot Pro for JavaScript 8.4.2911
  • June 15, 2015: Initial release