Search

Laravel 8 Create Events in Fullcalendar using Ajax

post-title

FullCalendar is a open-source, lightweight JavaScript library to create dynamic, draggable event calendars on modern web applications. FullCalendar works well with all front-end frameworks including Vue, React, Angular and Javascript.

This tutorial explains how to use FullCalendar in Laravel 8 and create events using jQuery Ajax. In this tutorial, we will explain step by step from the scratch. The tutorial includes following steps:

  • Step 1: Create fresh Laravel application
  • Step 2: Configure database
  • Step 3: Create and run migration
  • Step 4: Create Event model
  • Step 5: Create controller and add methods
  • Step 6: Create new routes
  • Step 7: Create calendar.blade.php blade file
  • Step 8: Testing FullCalendar application

So let's start tutorial and create fresh Laravel application.

Step 1: Create fresh Laravel application

As we are starting from the scratch, first create fresh Laravel application using Composer command. Composer is the best companion to install and download PHP library from command line. Start Terminal and run the following command to create new Laravel application.

composer create-project laravel/laravel calendar --prefer-dist

After the project is created, change Terminal directory to project root.

cd calendar

Step 2: Configure database

Now open the Laravel project into your favourite IDE. In this step, we will configure Laravel database with MySQL. Open .env file from the root of project and change below credentials with your MySQL.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=calendar
DB_USERNAME=root
DB_PASSWORD=secret

Step 3: Create and run migration

Now we need a table which store events. For that, run the following Artisan command to generate migration file at database/migrations directory.

php artisan make:migration create_events_table

Now open this migration class and add the table fields.

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateEventsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('events', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->string('start');
            $table->string('end');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('events');
    }
}

After table fields, defined run migrate command to create database tables.

php artisan migrate

Step 4: Create Event model

We also need to create model class to run query into database. Run the below Artisan command to create model at app/Models directory.

php artisan make:model Event

In the Even model class, create $fillable attribute with column fields for assinable.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Event extends Model
{
    use HasFactory;

    /**
     * The attributes that are mass assignable.
     *
     * @var string[]
     */
    protected $fillable = [
        'title',
        'start',
        'end',
    ];
}

Step 5: Create controller and add methods

In this step, we will create controller class and write application logic in the class methods. Run the following command to create controller class at app/Http/Controllers directory.

php artisan make:controller EventController

Now open the controller class and add the below methods into it.

<?php

namespace App\Http\Controllers;

use Validator;
use App\Models\Event;
use Illuminate\Http\Request;

class EventController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index(Request $request)
    {
        if ($request->ajax()) {
            $events = Event::whereDate('start', '>=', $request->start)
                ->whereDate('end', '<=', $request->end)
                ->get();

            return response()->json($events);
        }
        
        return view('calendar');
    }

    /**
     * Create new event.
     *
     * @return \Illuminate\Http\Response
     */
    public function create(Request $request)
    {
        $input = $request->only(['title', 'start', 'end']);

        $request_data = [
            'title' => 'required',
            'start' => 'required',
            'end' => 'required'
        ];

        $validator = Validator::make($input, $request_data);

        // invalid request
        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => 'Something went wrong, please check all parameters',
            ]);
        }

        $event = Event::create([
            'title' => $input['title'],
            'start' => $input['start'],
            'end' => $input['end'],
        ]);

        return response()->json([
            'success' => true,
            'data' => $event
        ]);
    }

    /**
     * update current event.
     *
     * @return \Illuminate\Http\Response
     */
    public function edit(Request $request)
    {
        $input = $request->only(['id', 'title', 'start', 'end']);

        $request_data = [
            'id' => 'required',
            'title' => 'required',
            'start' => 'required',
            'end' => 'required'
        ];

        $validator = Validator::make($input, $request_data);

        // invalid request
        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => 'Something went wrong, please check all parameters',
            ]);
        }

        $event = Event::where('id', $input['id'])
            ->update([
                'title' => $request['title'],
                'start' => $request['start'],
                'end' => $request['end'],
            ]);

        return response()->json([
            'success' => true,
            'data' => $event
        ]);
    }

    /**
     * Destroy the event.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy(Request $request)
    {
        Event::where('id', $request->id)
            ->delete();

        return response()->json([
            'success' => true,
            'message' => 'Event removed successfully.'
        ]);
    }
}

Step 6: Create new routes

As we have created controller class, now we need to create new routes for controller methods. Open routes/web.php and add new routes in it.

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\EventController;

Route::get('calendar', [EventController::class, 'index'])->name('calendar.index');
Route::post('calendar/create-event', [EventController::class, 'create'])->name('calendar.create');
Route::patch('calendar/edit-event', [EventController::class, 'edit'])->name('calendar.edit');
Route::delete('calendar/remove-event', [EventController::class, 'destroy'])->name('calendar.destroy');

Step 7: Create calendar.blade.php blade file

In the first controller method we are returning blade view where we will render HTML code. So in the last coding step, we will create Laravel's blade view calendar.blade.php file at resources/views directory.

<!doctype html>
<html>
<head>
    <title>FullCalndar example</title>
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.10.2/fullcalendar.min.css" />
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.2/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/izitoast/1.4.0/css/iziToast.min.css" />
</head>
<body>
    <div class="container">
        <div class="row m-3">
            <h1>FullCalndar example</h1>
            <hr>
            <div class="col-12">
                <div id='calendar'></div>
            </div>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.10.2/fullcalendar.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.2/dist/js/bootstrap.bundle.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/izitoast/1.4.0/js/iziToast.min.js"></script>
    <script type="text/javascript">
        $(document).ready(function() {

            // pass _token in all ajax
             $.ajaxSetup({
                headers: {
                    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                }
            });

            // initialize calendar in all events
            var calendar = $('#calendar').fullCalendar({
                editable: true,
                events: "{{ route('calendar.index') }}",
                displayEventTime: true,
                eventRender: function (event, element, view) {
                    if (event.allDay === 'true') {
                            event.allDay = true;
                    } else {
                            event.allDay = false;
                    }
                },
                selectable: true,
                selectHelper: true,
                select: function (start, end, allDay) {
                    var event_name = prompt('Event Name:');
                    if (event_name) {
                        var start = $.fullCalendar.formatDate(start, "YYYY-MM-DD HH:mm:ss");
                        var end = $.fullCalendar.formatDate(end, "YYYY-MM-DD HH:mm:ss");
                        $.ajax({
                            url: "{{ route('calendar.create') }}",
                            data: {
                                title: event_name,
                                start: start,
                                end: end
                            },
                            type: 'post',
                            success: function (data) {
                               iziToast.success({
                                    position: 'topRight',
                                    message: 'Event created successfully.',
                                });

                                calendar.fullCalendar('renderEvent', {
                                    id: data.id,
                                    title: event_name,
                                    start: start,
                                    end: end,
                                    allDay: allDay
                                }, true);
                                calendar.fullCalendar('unselect');
                            }
                        });
                    }
                },
                eventDrop: function (event, delta) {
                    var start = $.fullCalendar.formatDate(event.start, "YYYY-MM-DD HH:mm:ss");
                    var end = $.fullCalendar.formatDate(event.end, "YYYY-MM-DD HH:mm:ss");

                    $.ajax({
                        url: "{{ route('calendar.edit') }}",
                        data: {
                            title: event.event_name,
                            start: start,
                            end: end,
                            id: event.id,
                        },
                        type: "POST",
                        success: function (response) {
                            iziToast.success({
                                position: 'topRight',
                                message: 'Event updated successfully.',
                            });
                        }
                    });
                },
                eventClick: function (event) {
                    var eventDelete = confirm('Are you sure to remove event?');
                    if (eventDelete) {
                        $.ajax({
                            type: "post",
                            url: "{{ route('calendar.destroy') }}",
                            data: {
                                id: event.id,
                                _method: 'delete',
                            },
                            success: function (response) {
                                calendar.fullCalendar('removeEvents', event.id);
                                iziToast.success({
                                    position: 'topRight',
                                    message: 'Event removed successfully.',
                                });
                            }
                        });
                    }
                }   
            });
        });
    </script>
</body>
</html>

As you can see we are using FullCalendar CDN file. $('#calendar').fullCalendar() will initialize FullCalendar with options. The other options, we are using to create, edit or delete event using FullCalendar API. Then we are creating ans sending Ajax request to controller methods to create, update or remove event record to events table.

Step 8: Testing FullCalendar application

In the last step, we test the application. Start Laravel server using php artisan serve command and open the http://localhost:8000/calendar url into Browser. You will see Calendar with current month.

Now try to add new event on any date. It will ask to input event name. Same way you can remove event on clicking on it.

Conclusion

In the end of tutorial, we have learned how to integrate FullCalendar into Laravel 8 application and create, update and remove events from FullCalendar using Ajax. We hope you enjoy this tutorial article and it will help in your development. Thanks for giving time in reading the article.