Full Calendar - ASP.NET Web API And AngularJS

Introduction

As you know, in the professional world, we have to do many things such as meetings, business trips, and training sessions. Therefore all that must be organized by using a calendar.

In this article, we will demonstrate how we can use a Full Calendar plugin based on ASP.Net Web API (Back-end) and AngularJS (Front-end). Here what we are doing exactly is to customize the FullCalendar plugin in order to be able to perform CRUD operations. I'd like to remind you that you should have some basic knowledge of Web API and AngularJS. I hope you will like it.

Prerequisites

Make sure you have installed Visual Studio 2017 (.NET Framework 4.6.1) and SQL Server.

In this post, we are going to:

  • Create Database.
  • Create MVC application.
  • Configuring Entity framework ORM to connect to a database.
  • Create our Calendar controller.
  • Create AngularJS file.
  • Create HTML page for a demo.                                     

SQL Database part

Here, you will find the script to create database and table.

Create Database

  1. USE [master]  
  2. GO  
  3. /****** Object:  Database [CalendarDB]    Script Date: 1/24/2018 9:11:39 PM ******/  
  4. CREATE DATABASE [CalendarDB]  
  5.  CONTAINMENT = NONE  
  6.  ON  PRIMARY   
  7. NAME = N'CalendarDB', FILENAME = N'c:\Program Files (x86)\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\CalendarDB.mdf' , SIZE = 4096KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )  
  8.  LOG ON   
  9. NAME = N'CalendarDB_log', FILENAME = N'c:\Program Files (x86)\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\CalendarDB_log.ldf' , SIZE = 1024KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)  
  10. GO  
  11. ALTER DATABASE [CalendarDB] SET COMPATIBILITY_LEVEL = 110  
  12. GO  
  13. IF (1 = FULLTEXTSERVICEPROPERTY('IsFullTextInstalled'))  
  14. begin  
  15. EXEC [CalendarDB].[dbo].[sp_fulltext_database] @action = 'enable'  
  16. end  
  17. GO  
  18. ALTER DATABASE [CalendarDB] SET ANSI_NULL_DEFAULT OFF   
  19. GO  
  20. ALTER DATABASE [CalendarDB] SET ANSI_NULLS OFF   
  21. GO  
  22. ALTER DATABASE [CalendarDB] SET ANSI_PADDING OFF   
  23. GO  
  24. ALTER DATABASE [CalendarDB] SET ANSI_WARNINGS OFF   
  25. GO  
  26. ALTER DATABASE [CalendarDB] SET ARITHABORT OFF   
  27. GO  
  28. ALTER DATABASE [CalendarDB] SET AUTO_CLOSE OFF   
  29. GO  
  30. ALTER DATABASE [CalendarDB] SET AUTO_CREATE_STATISTICS ON   
  31. GO  
  32. ALTER DATABASE [CalendarDB] SET AUTO_SHRINK OFF   
  33. GO  
  34. ALTER DATABASE [CalendarDB] SET AUTO_UPDATE_STATISTICS ON   
  35. GO  
  36. ALTER DATABASE [CalendarDB] SET CURSOR_CLOSE_ON_COMMIT OFF   
  37. GO  
  38. ALTER DATABASE [CalendarDB] SET CURSOR_DEFAULT  GLOBAL   
  39. GO  
  40. ALTER DATABASE [CalendarDB] SET CONCAT_NULL_YIELDS_NULL OFF   
  41. GO  
  42. ALTER DATABASE [CalendarDB] SET NUMERIC_ROUNDABORT OFF   
  43. GO  
  44. ALTER DATABASE [CalendarDB] SET QUOTED_IDENTIFIER OFF   
  45. GO  
  46. ALTER DATABASE [CalendarDB] SET RECURSIVE_TRIGGERS OFF   
  47. GO  
  48. ALTER DATABASE [CalendarDB] SET  DISABLE_BROKER   
  49. GO  
  50. ALTER DATABASE [CalendarDB] SET AUTO_UPDATE_STATISTICS_ASYNC OFF   
  51. GO  
  52. ALTER DATABASE [CalendarDB] SET DATE_CORRELATION_OPTIMIZATION OFF   
  53. GO  
  54. ALTER DATABASE [CalendarDB] SET TRUSTWORTHY OFF   
  55. GO  
  56. ALTER DATABASE [CalendarDB] SET ALLOW_SNAPSHOT_ISOLATION OFF   
  57. GO  
  58. ALTER DATABASE [CalendarDB] SET PARAMETERIZATION SIMPLE   
  59. GO  
  60. ALTER DATABASE [CalendarDB] SET READ_COMMITTED_SNAPSHOT OFF   
  61. GO  
  62. ALTER DATABASE [CalendarDB] SET HONOR_BROKER_PRIORITY OFF   
  63. GO  
  64. ALTER DATABASE [CalendarDB] SET RECOVERY SIMPLE   
  65. GO  
  66. ALTER DATABASE [CalendarDB] SET  MULTI_USER   
  67. GO  
  68. ALTER DATABASE [CalendarDB] SET PAGE_VERIFY CHECKSUM    
  69. GO  
  70. ALTER DATABASE [CalendarDB] SET DB_CHAINING OFF   
  71. GO  
  72. ALTER DATABASE [CalendarDB] SET FILESTREAM( NON_TRANSACTED_ACCESS = OFF )   
  73. GO  
  74. ALTER DATABASE [CalendarDB] SET TARGET_RECOVERY_TIME = 0 SECONDS   
  75. GO  
  76. ALTER DATABASE [CalendarDB] SET  READ_WRITE   
  77. GO  

Create Table

After creating database, we will move to create events table.

Events Table

  1. USE [CalendarDB]  
  2. GO  
  3. /****** Object:  Table [dbo].[Events]    Script Date: 1/24/2018 9:12:14 PM ******/  
  4. SET ANSI_NULLS ON  
  5. GO  
  6. SET QUOTED_IDENTIFIER ON  
  7. GO  
  8. SET ANSI_PADDING ON  
  9. GO  
  10.   
  11. CREATE TABLE [dbo].[Events](  
  12. [EventID] [int] IDENTITY(1,1) NOT NULL,  
  13. [EventTitle] [varchar](50) NULL,  
  14. [EventDescription] [varchar](50) NULL,  
  15. [StartDate] [datetime] NULL,  
  16. [EndDate] [datetime] NULL,  
  17.  CONSTRAINT [PK_Events] PRIMARY KEY CLUSTERED   
  18. (  
  19. [EventID] ASC  
  20. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ONON [PRIMARY]  
  21. ON [PRIMARY]  
  22. GO  
  23. SET ANSI_PADDING OFF  
  24. GO  

Create your MVC application

Open Visual Studio and select File >> New Project.

The "New Project" window will pop up. Select ASP.NET Web Application (.NET Framework), name your project, and click OK.

ASP.NET

Next, a new dialog will pop up for selecting the template. We are going choose Web API template and click Ok.

ASP.NET

Once our project is created, we will add ADO.NET Entity Data Model.

Adding ADO.NET Entity Data Model

From solution explorer, right click on the project name, click Add >> Add New Item.

A dialog box will pop up, inside Visual C#, select Data then ADO.NET Entity Data Model, and enter the name for your DbContext model as CalendarDB, then click Add.

ASP.NET

As you can see, we have 4 model contents, we are selecting the first approach (EF Designer from a database).

ASP.NET

In the next step, we need to select server name, then via drop-down list in connect to a database section. You must choose your database name and finally click OK.

ASP.NET

After that, Entity Data Model Wizard dialog will pop up for choosing objects which will be used in our application. We are selecting the events table then click finish.

Finally, we see that EDMX model generates events table as an object as shown below.

ASP.NET

ASP.NET
Create a controller

Now, we are going to create a controller. Right-click on the controllers folder> > Add >> Controller>> selecting Web API 2 Controller – Empty >> click Add. In the next dialog, name the controller as CalendarController and then click Add.

ASP.NET

ASP.NET

CalendarController.cs

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Net;  
  5. using System.Net.Http;  
  6. using System.Web.Http;  
  7.   
  8. namespace DemoCalendarWebAPI.Controllers  
  9. {  
  10.     [RoutePrefix("api/Calendar")]  
  11.     public class CalendarController : ApiController  
  12.     {  
  13.         /// <summary>  
  14.         /// Gets all events from Events table  
  15.         /// </summary>  
  16.         /// <returns></returns>  
  17.         ///  
  18.         //[HttpGet]  
  19.         [Route("GetEvents")]  
  20.         public IHttpActionResult GetEvents()  
  21.         {  
  22.             using (CalendarDBEntities1 context = new CalendarDBEntities1())  
  23.             {  
  24.                 var eventsList = context.Events.ToList();  
  25.                 return Ok(eventsList);    
  26.             }  
  27.         }  
  28.   
  29.         /// <summary>  
  30.         /// Save or update event.  
  31.         /// </summary>  
  32.         /// <param name="eventObject"></param>  
  33.         /// <returns></returns>  
  34.         ///  
  35.         //[HttpPost]  
  36.         [Route("PostSaveOrUpdate")]  
  37.         public IHttpActionResult PostSaveOrUpdate(Event NewEvent)  
  38.         {  
  39.             using (CalendarDBEntities1 context = new CalendarDBEntities1())  
  40.             {  
  41.                 if(!ModelState.IsValid)  
  42.                 {  
  43.                     return BadRequest();  
  44.                 }  
  45.   
  46.                 var eventObj = context.Events.FirstOrDefault(e => e.EventID == NewEvent.EventID);  
  47.                 if(eventObj != null)  
  48.                 {  
  49.                     eventObj.EventTitle = NewEvent.EventTitle;  
  50.                     eventObj.EventDescription = NewEvent.EventDescription;  
  51.                     eventObj.StartDate = NewEvent.StartDate;  
  52.                     eventObj.EndDate = NewEvent.EndDate;  
  53.                 }  
  54.                 else  
  55.                 {  
  56.                     context.Events.Add(NewEvent);  
  57.                 }  
  58.   
  59.                 context.SaveChanges();  
  60.   
  61.                 return Ok();  
  62.             }  
  63.         }  
  64.   
  65.         /// <summary>  
  66.         /// Delete an event based on the given id.  
  67.         /// </summary>  
  68.         /// <param name="eventId"></param>  
  69.         /// <returns></returns>  
  70.         ///  
  71.         //[HttpDelete]  
  72.         [Route("DeleteEvent/{eventId:int}")]  
  73.         public IHttpActionResult DeleteEvent(int EventID)  
  74.         {  
  75.             using (CalendarDBEntities1 context = new CalendarDBEntities1())  
  76.             {  
  77.                 Event eventObj = context.Events.FirstOrDefault(e=>e.EventID == EventID);  
  78.   
  79.                 if(eventObj == null)  
  80.                 {  
  81.                     return NotFound();  
  82.                 }  
  83.   
  84.                 context.Events.Remove(eventObj);  
  85.                 context.SaveChanges();  
  86.   
  87.                 return Ok(eventObj);  
  88.             }  
  89.         }  
  90.   
  91.     }  
  92. }  

 As I mentioned previously, we are using Web API to create all the necessary methods which will be called from the browser.

Now, it's time to define all the methods to perform CRUD operations.

Let's begin with GetEvents() which is responsible to get all the events from the database. This method is decorated as you can see by [Route("GetEvents")] attribute that means if you would call this method, you should proceed as follows: api/Calendar/GetEvents.

Next, we have PostSaveOrUpdate() method which is used to add a new event or update it.

Here, the code snippet implemented is very simple. When we receive event object from HTTP request, we will search it based on EventId. If it already exists in the database that means the operation which will be performed is an update, otherwise we will add it to events table. 

One thing that I’d clarify, [Route("PostSaveOrUpdate")] attribute explains we should call the method as follows : /api/Calendar/PostSaveOrUpdate. 

Finally, the DeleteEvent method accepts EventId as a parameter and is used to delete an event based on the given EventId parameter. Let’s describe the code snippet of DeleteEvent method,

  1. Search an event based on the EventId parameter. To accomplish that, we used FirstOrDefault()    extension method.
  2. If the eventObj object is NULL, we will return NotFound() translated by 404 as status code result, otherwise, we will proceed to delete the returned object by using remove() extension method and finally, we will return OK() which is translated as 200 status code result. 

AngularJS Part

Add JavaScript File

In solution explorer, right-click the project name, Add >> JavaScript File.

App.js

  1.  var app = angular.module('App', ['ui.calendar''ui.bootstrap']);  
  2. app.controller('CalendarController', ['$scope''$http''uiCalendarConfig''$uibModal'function ($scope, $http, uiCalendarConfig, $uibModal) {  
  3.   
  4.     $scope.eventsTab = [];  
  5.     $scope.events = [$scope.eventsTab];  
  6.   
  7.     $scope.EventObj = {};  
  8.   
  9.     //Clear calendar  
  10.     function clearCalendar() {  
  11.         if (uiCalendarConfig.calendars.Calendar != null) {  
  12.             uiCalendarConfig.calendars.Calendar.fullCalendar('removeEvents');  
  13.         }  
  14.     }  
  15.   
  16.     //Gets all events from db  
  17.     function GetEvents() {  
  18.   
  19.         clearCalendar();  
  20.   
  21.         $http.get('/api/Calendar/GetEvents', {  
  22.             cache: false,  
  23.             params: {},  
  24.         }).then(function (response) {  
  25.   
  26.             angular.forEach(response.data, function (value) {  
  27.   
  28.                 $scope.eventsTab.push({  
  29.                     id: value.EventID,  
  30.                     title: value.EventTitle,  
  31.                     description: value.EventDescription,  
  32.                     start: new Date(parseInt(value.StartDate.substr(6))),  
  33.                     end: new Date(parseInt(value.EndDate.substr(6))),  
  34.                     backgroundColor: "#f9a712",  
  35.                     borderColor: "#8e8574"    
  36.                 });  
  37.   
  38.                 console.log($scope.eventsTab);  
  39.   
  40.             });  
  41.         });  
  42.     }  
  43.   
  44.     GetEvents();  
  45.   
  46.   
  47.     //Configure Calendar  
  48.     $scope.uiConfig = {  
  49.         calendar: {  
  50.             height: 450,  
  51.             editable: true,  
  52.             displayEventTime: true,  
  53.             header: {  
  54.                 left: 'prev,next today',  
  55.                 center: 'title',  
  56.                 right: 'month,agendaWeek,agendaDay'    
  57.             },  
  58.             selectable: true,  
  59.             select: function (start, end) {  
  60.                 var startDate = moment(start).format('YYYY/MM/DD');  
  61.                 var endDate = moment(end).format('YYYY/MM/DD');  
  62.   
  63.                 $scope.EventObj = {  
  64.                     EventID: 0,  
  65.                     EventTitle: '',  
  66.                     EventDescription: '',  
  67.                     StartDate: startDate,  
  68.                     EndDate: endDate  
  69.                 };  
  70.   
  71.                 $scope.ShowModal();  
  72.                  
  73.             },  
  74.             eventClick: function (event) {  
  75.   
  76.                 var startDate = moment(event.start).format('YYYY/MM/DD');  
  77.                 var endDate = moment(event.end).format('YYYY/MM/DD');  
  78.   
  79.                 $scope.EventObj = {  
  80.                     EventID: event.id,  
  81.                     EventTitle: event.title,  
  82.                     EventDescription: event.description,  
  83.                     StartDate: startDate,  
  84.                     EndDate: endDate  
  85.                 };  
  86.   
  87.                 $scope.ShowModal();  
  88.             }  
  89.   
  90.         }  
  91.   
  92.     };  
  93.   
  94.     // Popup modal  
  95.     $scope.ShowModal = function () {  
  96.   
  97.         var modalInstance = $uibModal.open({  
  98.             templateUrl: 'modalPopUp.html',  
  99.             controller: 'modalCtrl',  
  100.             backdrop: 'static',  
  101.             resolve: {  
  102.                 EventObj: function () {  
  103.                     return $scope.EventObj;  
  104.                 }  
  105.             }  
  106.         });  
  107.   
  108.         modalInstance.result.then(function (result) {  
  109.   
  110.             switch (result.operation) {  
  111.                 
  112.                 case 'AddOrUpdate':  
  113.                     $http({  
  114.                         method: 'POST',  
  115.                         url: '/api/Calendar/PostSaveOrUpdate',  
  116.                         data: $scope.EventObj  
  117.                     }).then(function (response) {  
  118.                         console.log("Added ^_^");  
  119.                         GetEvents();  
  120.   
  121.                         }, function errorRollBak() {  
  122.                             console.log("Something Wrong !!");  
  123.                         });  
  124.                     break;  
  125.   
  126.                 case 'Delete':  
  127.                     $http({  
  128.                         method: 'DELETE',  
  129.                         url: '/api/Calendar/DeleteEvent/' + $scope.EventObj.EventID  
  130.   
  131.                     }).then(function (response) {  
  132.   
  133.                         GetEvents();  
  134.   
  135.                     }, function errorRollBack() {  
  136.   
  137.                         console.log("Something Wrong !!");  
  138.   
  139.                     });  
  140.   
  141.   
  142.                     break;  
  143.   
  144.                 default:  
  145.                     break;  
  146.             }  
  147.   
  148.         }, function () {  
  149.             $log.info('modal-component dismissed at: ' + new Date());  
  150.         })  
  151.   
  152.     }  
  153.   
  154.   
  155. }])  
  156.   
  157.   
  158. //modalCtrl controller will be used to perform CRUD Operation.  
  159. app.controller('modalCtrl', ['$scope''$uibModalInstance''EventObj'function ($scope, $uibModalInstance, EventObj) {  
  160.   
  161.     $scope.EventObj = EventObj;  
  162.   
  163.     $scope.AddOrUpdateEvent = function () {  
  164.   
  165.             $uibModalInstance.close({ event: $scope.EventObj, operation: 'AddOrUpdate' });  
  166.     }  
  167.   
  168.     $scope.DeleteEvent = function () {  
  169.         $uibModalInstance.close({ event: $scope.EventObj, operation: 'Delete' });  
  170.     }  
  171.   
  172.     $scope.CancelEvent = function () {  
  173.         $uibModalInstance.dismiss('cancel');  
  174.     }  
  175.   
  176.   
  177. }])  

Let's explain how to configure our calendar.

As you can see above, to configure calendar, we need to provide so many properties such as:

  • height: represents the height of calendar.
  • header: contains the information such as title, navigation calendar (previous, next, today)

which will be shown at top of the calendar.

  • selectable: accepts as parameter Boolean value(true/false) and means if calendar will be

selectable or not.

  • eventClick: will be triggered when a user clicks an event.

Finally, Show modal function is used to perform CRUD operations.

Add HTML page

To add html page, right click the project name >> Add >> HTML page

Calendar.html

  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4.     <meta charset="utf-8" />  
  5.     <title>.: Demo Calendar :.</title>  
  6.     <!-- CSS -->  
  7.     <link href="Content/bootstrap.min.css" rel="stylesheet" />  
  8.     <link href="Content/fullcalendar.css" rel="stylesheet" />  
  9. </head>  
  10. <body>  
  11.   
  12.     <div ng-app="App" ng-controller="CalendarController">  
  13.   
  14.         <script type="text/ng-template" id="modalPopUp.html">  
  15.             <div class="modal-header">  
  16.                 <h3 class="modal-title"> CUD Events </h3>  
  17.             </div>  
  18.             <div class="modal-body">  
  19.   
  20.                 <div class="form-group">  
  21.                     <label>Event Title : </label>  
  22.                     <input type="text" ng-model="EventObj.EventTitle"  class="form-control"  />  
  23.                 </div>  
  24.   
  25.                 <div class="form-group">  
  26.                     <label>Description : </label>  
  27.                     <input type="text" ng-model="EventObj.EventDescription"  class="form-control" />  
  28.                 </div>  
  29.   
  30.                 <div class="form-group">  
  31.                     <label>Date (Start - END) : </label>  
  32.                     <span>{{EventObj.StartDate}} - {{EventObj.EndDate}}</span>  
  33.                 </div>  
  34.             </div>  
  35.             <div class="modal-footer">  
  36.                 <button class="btn btn-primary" type="button" ng-click="AddOrUpdateEvent()">Add Or Update Event</button>  
  37.                 <button class="btn btn-success" type="button" ng-show="EventObj.EventID > 0" ng-click="DeleteEvent()">Delete Event</button>  
  38.                 <button class="btn btn-info" type="button" ng-click="CancelEvent()">Cancel Event</button>  
  39.             </div>  
  40.   
  41.         </script>  
  42.   
  43.         <div class="CalenderClass">  
  44.   
  45.             <div class="row">  
  46.                 <div class="col-md-12">  
  47.                     <div ui-calendar="uiConfig.calendar" class="calendar"  ng-model="events" calendar="Calendar"></div>  
  48.                 </div>  
  49.             </div>  
  50.         </div>         
  51.     </div>  
  52.   
  53.     <!-- JS -->  
  54.     <script src="Scripts/moment.js"></script>  
  55.     <script src="Scripts/jquery-1.10.2.min.js"></script>  
  56.     <script src="Scripts/bootstrap.js"></script>  
  57.     <script src="Scripts/angular.js"></script>  
  58.     <script src="Scripts/calendar.js"></script>  
  59.     <script src="Scripts/fullcalendar.js"></script>  
  60.     <script src="Scripts/gcal.js"></script>  
  61.     <script src="Scripts/ui-bootstrap-tpls.min.js"></script>  
  62.     <script src="Scripts/App.js"></script>  
  63.   
  64. </body>  
  65. </html>  

Note

Do not forget to add the following libraries within Calendar.html page.

  1. <!-- JS -->  
  2. <script src="Scripts/moment.js"></script>  
  3. <script src="Scripts/jquery-1.10.2.min.js"></script>  
  4. <script src="Scripts/bootstrap.js"></script>  
  5. <script src="Scripts/angular.js"></script>  
  6. <script src="Scripts/calendar.js"></script>  
  7. <script src="Scripts/fullcalendar.js"></script>  
  8. <script src="Scripts/gcal.js"></script>  
  9. <script src="Scripts/ui-bootstrap-tpls.min.js"></script>  
  10. <script src="Scripts/App.js"></script>  

You can download them from Here

Demo

Now, our Calendar application is ready. We can run and see the output in the browser.

ASP.NET

ASP.NET

That’s all. Please send your feedback and queries in the comments box.