DEV Community

timnans
timnans

Posted on • Edited on

Rails Calendar with Tui and StimulusJs

We will create a Rails 6 calendar Application using StimulusJs and Tui Calendar. To begin, we first create a new Rails application.

rails new calendar --database=postgresql
Enter fullscreen mode Exit fullscreen mode

Once we have created our application, we then proceed to install StimulusJs.

rails webpacker:install:stimulus
Enter fullscreen mode Exit fullscreen mode

We then proceed to install Tui Calendar using yarn.

yarn add tui-calendar
Enter fullscreen mode Exit fullscreen mode

Modeling Data

Once we have all our dependencies installed we can proceed to scaffolding the data we wish to store in our application. We would create a model called Event with the following attributes and types:

CalendarID : Integer
Title : string
Location: string 
start: datetime
end: datetime
Enter fullscreen mode Exit fullscreen mode

We run our scaffold generator to create the model, views and the controller for our data.

rails g scaffold schedule title:string calendar_id:integer start:datetime end:datetime location:string 
rails db:migrate
Enter fullscreen mode Exit fullscreen mode

We then define the root path of our application

config/routes.rb
Enter fullscreen mode Exit fullscreen mode
root 'schedules#index'
Enter fullscreen mode Exit fullscreen mode

Displaying the Calendar

Once the initial setup is done, we can now proceed to display our calendar. Navigate to
app/views/schedules/index.html.erb and clear the scaffolded index page. We create a div tag and give it an id of calendar. we also provide some json data to the div tag. We wrap this div tag in a stimulus controller called calendar.

app/views/schedules/index.html.erb
Enter fullscreen mode Exit fullscreen mode
<div data-controller="calendar">
<%= tag.div nil, data: {schedules: @schedules .to_json}, id: "calendar"%>
</div>
Enter fullscreen mode Exit fullscreen mode

We then proceed to create our stimulus controller called ‘calendar_controller.js’ under the path app/javascript/controllers/calendar_controller.js and export the class

import { Controller } from "stimulus"
export default class extends Controller {
  connect() {
  }
}
Enter fullscreen mode Exit fullscreen mode

Once we have done that we import several libraries:

import Rails from "@rails/ujs"
import 'tui-time-picker/dist/tui-time-picker.css';
import "tui-calendar/dist/tui-calendar.css";
import Calendar from "tui-calendar";
Enter fullscreen mode Exit fullscreen mode

Note: We simply follow the steps on the github document page to import Calendar and its stylesheets. Once we have done that, we create a new instance of Calendar, and define its attributes such as id, name, defaultView, color. This provided in the code below:

 calendar = new Calendar(document.getElementById('calendar'), {
        id: "1",
        name: "My Calendar",
        defaultView: 'month',
        color: '#00a9ff',
          bgColor: '#00a9ff',
          dragBgColor: '#00a9ff',
          borderColor: 'red',

        milestone: true,    // Can be also ['milestone', 'task']
        scheduleView: true,  // Can be also ['allday', 'time']
        useCreationPopup: true,
        useDetailPopup: true,
        template: {

          popupDetailRepeat: function(schedule) {
            return 'Repeat : ' + schedule.recurrenceRule;
          },

          popupStateFree: function() {
            return 'Free';
          },
            milestone: function(schedule) {
                return '<span style="color:red;"><i class="fa fa-flag"></i> ' + schedule.title + '</span>';
            },
            milestoneTitle: function() {
                return 'Milestone';
            },
            task: function(schedule) {
                return '&nbsp;&nbsp;#' + schedule.title;
            },
            taskTitle: function() {
                return '<label><input type="checkbox" />Task</label>';
            },
            allday: function(schedule) {
                return schedule.title + ' <i class="fa fa-refresh"></i>';
            },
            alldayTitle: function() {
                return 'All Day';
            },
            time: function(schedule) {
                return schedule.title + ' <i class="fa fa-refresh"></i>' + schedule.start;
            }
        },
        month: {
            daynames: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
            startDayOfWeek: 0,
            narrowWeekend: true
        },
        week: {
            daynames: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
            startDayOfWeek: 0,
            narrowWeekend: true
        }
    });
Enter fullscreen mode Exit fullscreen mode

After saving our changes, our calendar becomes viewable.
Tui Calendar

Displaying Data on the Calendar

Getting Calendar Data

We must define a method that helps us obtain the calendar data. We have already passed the data as json to our index page, so we must parse the data to make it available in our calendar controller. We store this parse information in a variable called schedules. Once we have done that, we iterate over the schedule and create a calendar Schedule that would display each element on the calendar.

    getCalendardata(){
        var schedules = JSON.parse(document.querySelector("#calendar").dataset.schedules);
        window.schedules = schedules;
        schedules.forEach(schedule => {
        this.calendar.createSchedules([
        {
          id: schedule.id,
          calendarId: '1',
          title: schedule.title,
          category: 'time',
          dueDateClass: schedule.dueDateClass,
          location: schedule.location,
          start: schedule.start,
          end: schedule.end
        }
        ])
        });
      }
Enter fullscreen mode Exit fullscreen mode

We then call this method underr connect(){} in Our Calendar Controller.

connect() {
      this.getCalendardata()
}
Enter fullscreen mode Exit fullscreen mode

Creating Calendar schedules

First we must make some changes to our schedules controller. After a successful update, create or destroy action, we do not want to be redirected. To solve this, we simply comment out several lines from our controller.

 def create
    @schedule = Schedule.new(schedule_params)
    respond_to do |format|
      if @schedule.save
        # format.html { redirect_to @schedule, notice: "Schedule was successfully created." }
        format.json { render :show, status: :created, location: @schedule }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @schedule.errors, status: :unprocessable_entity }
      end
    end
  end

  def update
    respond_to do |format|
      if @schedule.update(schedule_params)
        # format.html { redirect_to @schedule, notice: "Schedule was successfully updated." }
        format.json { render :show, status: :ok, location: @schedule }
      else
        format.html { render :edit, status: :unprocessable_entity }
        format.json { render json: @schedule.errors, status: :unprocessable_entity }
      end
    end
  end

  def destroy
    @schedule.destroy
    respond_to do |format|
      # format.html { redirect_to schedules_url, notice: "Schedule was successfully destroyed." }
      format.json { head :no_content }
    end
  end
Enter fullscreen mode Exit fullscreen mode

Secondly, we would relax the strong parameters on our controllers a bit.

    def schedule_params
      params.permit(:title, :calendar_id, :start, :end, :location)
    end
Enter fullscreen mode Exit fullscreen mode

To begin display events on the calendar we must first define a javascript method that creates events. We define a method called createCalendarSchedule. Tui provides certain event handlers that we can use to create events. We will use ‘beforeCreateSchedule’ to create a schedule. When a user clicks on the calendar, a popup form is presented. When data is filled in the popup, we collect the information, create a formdata, and submit it via Rails.ajax

reateCalendarSchedule(){
        let calendar = this.calendar;
        calendar.on('beforeCreateSchedule', function(event) {
        var triggerEventName = event.triggerEventName;
        var schedule =  {
          id: 1,
          calendarId: '1',
          title: event.title,
          category: 'time',
          location: event.location,
          start: event.start,
          end: event.end
        }
        if (triggerEventName === 'click') {
            // open writing simple schedule popup
            // schedule = {...};
        } else if (triggerEventName === 'dblclick') {
            // open writing detail schedule popup
            // schedule = {...};
        }

        calendar.createSchedules([schedule]);
        let formData = new FormData()
        formData.append('title', schedule.title);
        formData.append('category', schedule.category);
        formData.append('start', schedule.start._date);
        formData.append('end', schedule.end._date);
        formData.append('location', schedule.location);

        Rails.ajax({
          type: "POST",
          url: '/schedules',
          data: formData
        })

      });
      } 
Enter fullscreen mode Exit fullscreen mode

We then call this method under connect(){} in Our Calendar Controller.

connect() {
      this.getCalendardata()
      this.createCalendarSchedule()
  }
Enter fullscreen mode Exit fullscreen mode

Tui Calendar

Updating Calendar Events

We would use another event handler to update calendar schedules. When we click on an already created schedule, a pop would appear that would allow us to edit or delete this schedule. We would use ‘beforeUpdateSchedule’ event to handle submitting our data.

updatedCalendarSchedule(){
        let calendar = this.calendar;
        calendar.on('beforeUpdateSchedule', function(event) {
          var schedule = event.schedule;
          var changes = event.changes;
          var formUpdate = new FormData()    
          if (changes.end) {
          formUpdate.append("end", changes.end._date)    
          }
          if (changes.start) {
          formUpdate.append("start", changes.start._date)    
          }
          if (changes.title) {
          formUpdate.append("title", changes.title)  
          }
          if (changes.category) {
          formUpdate.append("category", changes.category)  
          }
          calendar.updateSchedule(schedule.id, schedule.calendarId, changes);

          Rails.ajax({
          type: "PATCH",
          url: '/schedules/'+ schedule.id,
          data: formUpdate
          })

          });
      }
Enter fullscreen mode Exit fullscreen mode

We create a form with our updated data and submit it via Rails.ajax to ‘/schedules/:id’.
We then call this method under connect(){}

  connect() {
      this.updatedCalendarSchedule()
      this.getCalendardata()
      this.createCalendarSchedule()
  }
Enter fullscreen mode Exit fullscreen mode

Tui Calendar

Deleting Calendar Events

We now define a method that uses ‘the BeforeDeleteSchedule’ event handler to delete a schedule entry. This event is called when we click on a schedule on the calendar and click on ‘Delete’. The function makes a request via Rails.ajax to delete with selected schedule based on its ID.

      deleteCalendarSchedule(){
        let calendar = this.calendar
       calendar.on('beforeDeleteSchedule', function(event) {
          var schedule = event.schedule;
          calendar.deleteSchedule(schedule.id, schedule.calendarId)

          Rails.ajax({
            type: "DELETE",
            url: '/schedules/'+ schedule.id,
          })
          });
      }

Enter fullscreen mode Exit fullscreen mode

We then call this method under connect(){}

  connect() {
      this.deleteCalendarSchedule()
      this.updatedCalendarSchedule()
      this.getCalendardata()
      this.createCalendarSchedule()
  }
Enter fullscreen mode Exit fullscreen mode

Tui Calendar

README

This README would normally document whatever steps are necessary to get the application up and running.

Things you may want to cover:

  • Ruby version

  • System dependencies

  • Configuration

  • Database creation

  • Database initialization

  • How to run the test suite

  • Services (job queues, cache servers, search engines, etc.)

  • Deployment instructions

  • ...




Top comments (0)