CRUD operation on fullcalendar in ASP.NET MVC



Introduction

This is the 2nd part of the tutorial "Event/Scheduler calendar in asp.net MVC application". In the first part of this tutorial, we have seen how to display events in fullcalender from a database. Now in this 2nd part, we will implement CRUD (Create, Read, Update, Delete) operation on fullcalendar for managing event/schedule tasks to the database.

Here in this tutorial, we will see how we can add, edit and delete event in fullcalendar using a modal dialog. This will enhance our application in terms of Readability, Usability, and Better UI.

Ok, let's implement CRUD operation in the fullcalendar.




Before reading this 2nd part of the tutorial "Event/Scheduler calendar in asp.net MVC application", I will suggest you, read the previous part of this tutorial where we have shown you how to display events in fullcalendar from the database.

So, first of all, I will open the application in the Visual Studio what we have created in the previous part of this tutorial. You can download the application source code if you haven't done already.

Follow the following steps in order to implement "CRUD operation on fullcalendar in ASP.NET MVC".

Here In this article, I have used Visual Studio 2015

Step - 1: Add an MVC action for saving events to the database.

We have to add a new MVC action in our HomeController for saving events to the database. So open the HomeController.cs file and write this below MVC action for adding a new event and updating existing event to the database.
[HttpPost]
public JsonResult SaveEvent(Event e)
{
    var status = false;
    using (MyDatabaseEntities dc = new MyDatabaseEntities())
    {
        if (e.EventID > 0)
        {
            //Update the event
            var v = dc.Events.Where(a => a.EventID == e.EventID).FirstOrDefault();
            if (v != null)
            {
                v.Subject = e.Subject;
                v.Start = e.Start;
                v.End = e.End;
                v.Description = e.Description;
                v.IsFullDay = e.IsFullDay;
                v.ThemeColor = e.ThemeColor;
            }
        }
        else
        {
            dc.Events.Add(e);
        }
        dc.SaveChanges();
        status = true;
    }
    return new JsonResult { Data = new { status = status } };
}

Step-2: Add an another MVC action for deleting an event from the database.

We have to add an another MVC action in our HomeController for deleting events from the database. Write this below MVC action for deleting an event from the database.
[HttpPost]
public JsonResult DeleteEvent(int eventID)
{
    var status = false;
    using (MyDatabaseEntities dc = new MyDatabaseEntities())
    {
        var v = dc.Events.Where(a => a.EventID == eventID).FirstOrDefault();
        if (v != null)
        {
            dc.Events.Remove(v);
            dc.SaveChanges();
            status = true;
        }
    }
    return new JsonResult { Data = new { status = status} };
}

Step-3: Update the view page of the index action of HomeController.

This is the complete view page, see the below HTML code for the view page where we are generating the calendar control for displaying and managing events/schedule tasks on fullcalender. We have many changes on this view page for enabling CRUD operation. Let me explain line by line.
@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>
<div id="calender"></div>

<div id="myModal" class="modal fade" role="dialog">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal">&times;</button>
                <h4 class="modal-title"><span id="eventTitle"></span></h4>
            </div>
            <div class="modal-body">
                <button id="btnDelete" class="btn btn-default btn-sm pull-right">
                    <span class="glyphicon glyphicon-remove"></span> Remove
                </button>
                <button id="btnEdit" class="btn btn-default btn-sm pull-right" style="margin-right:5px;">
                    <span class="glyphicon glyphicon-pencil"></span> Edit
                </button>
                <p id="pDetails"></p>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
            </div>
        </div>
    </div>
</div>

<div id="myModalSave" class="modal fade" role="dialog">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal">&times;</button>
                <h4 class="modal-title">Save Event</h4>
            </div>
            <div class="modal-body">
                <form class="col-md-12 form-horizontal">
                    <input type="hidden" id="hdEventID" value="0" />
                    <div class="form-group">
                        <label>Subject</label>
                        <input type="text" id="txtSubject" class="form-control"/>
                    </div>
                    <div class="form-group">
                        <label>Start</label>
                        <div class="input-group date" id="dtp1">
                            <input type="text" id="txtStart" class="form-control" />
                            <span class="input-group-addon">
                                <span class="glyphicon glyphicon-calendar"></span>
                            </span>
                        </div>
                    </div>
                    <div class="form-group">
                        <div class="checkbox">
                            <label><input type="checkbox" id="chkIsFullDay" checked="checked" />  Is Full Day event</label>
                        </div>
                    </div>
                    <div class="form-group" id="divEndDate" style="display:none">
                        <label>End</label>
                        <div class="input-group date" id="dtp2">
                            <input type="text" id="txtEnd" class="form-control" />
                            <span class="input-group-addon">
                                <span class="glyphicon glyphicon-calendar"></span>
                            </span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label>Description</label>
                        <textarea id="txtDescription" rows="3" class="form-control"></textarea>
                    </div>
                    <div class="form-group">
                        <label>Theme Color</label>
                        <select id="ddThemeColor" class="form-control">
                            <option value="">Default</option>
                            <option value="red">Red</option>
                            <option value="blue">Blue</option>
                            <option value="black">Black</option>
                            <option value="green">Green</option>
                        </select>
                    </div>
                    <button type="button" id="btnSave" class="btn btn-success">Save</button>
                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                </form>
            </div>
        </div>
    </div>
</div>

<link href="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.4.0/fullcalendar.min.css" rel="stylesheet" />
<link href="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.4.0/fullcalendar.print.css" rel="stylesheet" media="print"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/css/bootstrap-datetimepicker.min.css" rel="stylesheet" />
@section Scripts{
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.4.0/fullcalendar.min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/js/bootstrap-datetimepicker.min.js"></script>
    <script>
        $(document).ready(function () {
            var events = [];
            var selectedEvent = null;
            FetchEventAndRenderCalendar();
            function FetchEventAndRenderCalendar() {
                events = [];
                $.ajax({
                    type: "GET",
                    url: "/home/GetEvents",
                    success: function (data) {
                        $.each(data, function (i, v) {
                            events.push({
                                eventID: v.EventID,
                                title: v.Subject,
                                description: v.Description,
                                start: moment(v.Start),
                                end: v.End != null ? moment(v.End) : null,
                                color: v.ThemeColor,
                                allDay: v.IsFullDay
                            });
                        })

                        GenerateCalender(events);
                    },
                    error: function (error) {
                        alert('failed');
                    }
                })
            }

            function GenerateCalender(events) {
                $('#calender').fullCalendar('destroy');
                $('#calender').fullCalendar({
                    contentHeight: 400,
                    defaultDate: new Date(),
                    timeFormat: 'h(:mm)a',
                    header: {
                        left: 'prev,next today',
                        center: 'title',
                        right: 'month,basicWeek,basicDay,agenda'
                    },
                    eventLimit: true,
                    eventColor: '#378006',
                    events: events,
                    eventClick: function (calEvent, jsEvent, view) {
                        selectedEvent = calEvent;
                        $('#myModal #eventTitle').text(calEvent.title);
                        var $description = $('<div/>');
                        $description.append($('<p/>').html('<b>Start:</b>' + calEvent.start.format("DD-MMM-YYYY HH:mm a")));
                        if (calEvent.end != null) {
                            $description.append($('<p/>').html('<b>End:</b>' + calEvent.end.format("DD-MMM-YYYY HH:mm a")));
                        }
                        $description.append($('<p/>').html('<b>Description:</b>' + calEvent.description));
                        $('#myModal #pDetails').empty().html($description);

                        $('#myModal').modal();
                    },
                    selectable: true,
                    select: function (start, end) {
                        selectedEvent = {
                            eventID: 0,
                            title: '',
                            description: '',
                            start: start,
                            end: end,
                            allDay: false,
                            color: ''
                        };
                        openAddEditForm();
                        $('#calendar').fullCalendar('unselect');
                    },
                    editable: true,
                    eventDrop: function (event) {
                        var data = {
                            EventID: event.eventID,
                            Subject: event.title,
                            Start: event.start.format('DD/MM/YYYY HH:mm A'),
                            End: event.end != null ? event.end.format('DD/MM/YYYY HH:mm A') : null,
                            Description: event.description,
                            ThemeColor: event.color,
                            IsFullDay: event.allDay
                        };
                        SaveEvent(data);
                    }
                })
            }

            $('#btnEdit').click(function () {
                //Open modal dialog for edit event
                openAddEditForm();
            })
            $('#btnDelete').click(function () {
                if (selectedEvent != null && confirm('Are you sure?')) {
                    $.ajax({
                        type: "POST",
                        url: '/home/DeleteEvent',
                        data: {'eventID': selectedEvent.eventID},
                        success: function (data) {
                            if (data.status) {
                                //Refresh the calender
                                FetchEventAndRenderCalendar();
                                $('#myModal').modal('hide');
                            }
                        },
                        error: function () {
                            alert('Failed');
                        }
                    })
                }
            })

            $('#dtp1,#dtp2').datetimepicker({
                format: 'DD/MM/YYYY HH:mm A'
            });

            $('#chkIsFullDay').change(function () {
                if ($(this).is(':checked')) {
                    $('#divEndDate').hide();
                }
                else {
                    $('#divEndDate').show();
                }
            });

            function openAddEditForm() {
                if (selectedEvent != null) {
                    $('#hdEventID').val(selectedEvent.eventID);
                    $('#txtSubject').val(selectedEvent.title);
                    $('#txtStart').val(selectedEvent.start.format('DD/MM/YYYY HH:mm A'));
                    $('#chkIsFullDay').prop("checked", selectedEvent.allDay || false);
                    $('#chkIsFullDay').change();
                    $('#txtEnd').val(selectedEvent.end != null ? selectedEvent.end.format('DD/MM/YYYY HH:mm A') : '');
                    $('#txtDescription').val(selectedEvent.description);
                    $('#ddThemeColor').val(selectedEvent.color);
                }
                $('#myModal').modal('hide');
                $('#myModalSave').modal();
            }

            $('#btnSave').click(function () {
                //Validation/
                if ($('#txtSubject').val().trim() == "") {
                    alert('Subject required');
                    return;
                }
                if ($('#txtStart').val().trim() == "") {
                    alert('Start date required');
                    return;
                }
                if ($('#chkIsFullDay').is(':checked') == false && $('#txtEnd').val().trim() == "") {
                    alert('End date required');
                    return;
                }
                else {
                    var startDate = moment($('#txtStart').val(), "DD/MM/YYYY HH:mm A").toDate();
                    var endDate = moment($('#txtEnd').val(), "DD/MM/YYYY HH:mm A").toDate();
                    if (startDate > endDate) {
                        alert('Invalid end date');
                        return;
                    }
                }
            
                var data = {
                    EventID: $('#hdEventID').val(),
                    Subject: $('#txtSubject').val().trim(),
                    Start: $('#txtStart').val().trim(),
                    End: $('#chkIsFullDay').is(':checked') ? null : $('#txtEnd').val().trim(),
                    Description: $('#txtDescription').val(),
                    ThemeColor: $('#ddThemeColor').val(),
                    IsFullDay: $('#chkIsFullDay').is(':checked')
                }
                SaveEvent(data);
                // call function for submit data to the server 
            })

            function SaveEvent(data) {
                $.ajax({
                    type: "POST",
                    url: '/home/SaveEvent',
                    data: data,
                    success: function (data) {
                        if (data.status) {
                            //Refresh the calender
                            FetchEventAndRenderCalendar();
                            $('#myModalSave').modal('hide');
                        }
                    },
                    error: function () {
                        alert('Failed');
                    }
                })
            }
        })
    </script>
}

Line 16-21: We have added 2 buttons in the modal popup used for displaying selected event, an edit, and a delete button. When users will click on the edit button we will open an edit form in an another modal dialog window for edit the selected event. We will use the same form for add a new event. And when users will click on the delete button we can call the delete action for deleting the selected event.

Line 31-88: We have added some HTML code here for creating a form for adding/updating event and for displaying the form in an another modal dialog window.

Line 92 and 96: Included bootstrap-datetimepicker JS and CSS file. This we will use for event start and end date field for getting a datetime from datetime picker.

Line 102: We have added a javascript function "FetchEventAndRenderCalendar" and move the ajax method into this function, what we have added in the previous part of this tutorial for fetching event data from the database.  This is done for re-use the function.

Line 110: Added EventID property of database event in the fullcalender event object, this is required for updating and deleting existing event from the database.

Line 143: Added a new line "selectedEvent = calEvent;"  in the eventClick event of the fullcalender for getting the selected event.

Line 155-168: We have added this for enable selecting a day or multiple days or timeslot by clicking and dragging in fullcalendar. We will open the add/edit form for creating a new event when user will select a day or multiple days or timeslots by clicking and dragging in fullcalendar.

Line 169-181: This allows users to drag an event from 1 timeslot to another. Using this drag and drop features, users can update time of an event easily.

Line 185-188: This is the edit button click event. When user will click on the edit button, we are calling an another javascript function "openAddEditForm" (see line 222-235) which is for opening the add/edit form in a modal popup dialog window.

Line 189-207: This is the delete button click event. When user will click on the delete button, we will call this ajax function we have written here in this click event for deleting the selected event from the database.

Line 209-211: Enabled datetime picker for the HTML element of  ID #dtp1 and #dtp2 which is for an Event Start and End date.

Line 213-220: This is the IsFullDay checkbox change event for show/hide the End date field according to the checkbox checked status.

Line 237-271: Save button click event for adding a new event/update existing event to the database. Here in this click event, we have done validation first and then we have called an another javascript "SaveEvent" (see in line 273) when validation success for saving the event data to the database.

Line 273-289: This is the javascript function we have used for submit event data to the server. 

Step-4: Run Application.

We have done all the steps. Now it's time to run the application. 


Hello ! My name is Sourav Mondal. I am a software developer working in Microsoft .NET technologies since 2010.

I like to share my working experience, research and knowledge through my site.

I love developing applications in Microsoft Technologies including Asp.Net webforms, mvc, winforms, c#.net, sql server, entity framework, Ajax, Jquery, web api, web service and more.