UI page using Fullcalendar. How do I fill in a field when clicking a date to create a new record?

Daniel Shock
Kilo Sage

I have been given a requirement to duplicate Atlassian Confluence calendar functionality in ServiceNow.  I have managed to create a UI page using the Fullcalendar library that displays records from my custom table using a date field named u_start.

This is what it looks like so far:

DanielShock_0-1686931061554.png 

 

If  you click on a blue even there, it opens up the record for editing or reference.  That is perfect.  If you click on the white space of a date, it opens up a modal window to create a new record.  That is also perfect.  

 

What is not perfect, is that the u_start field is not populated with the date that  you clicked on.  Here is what the modal looks like:

 

 

DanielShock_2-1686931244517.png

 

What I want is for the date that was clicked on to be filled in that start field.  I know I am getting the date because I have an alert setup in the code that tells me what date I clicked on.  I just don't know how to get over that last hump to put it in that field.

 

The other thing that does not work is the date picker on each of those start and end fields.  You can manually type in a date and click submit and it does create a new record correctly.  But click on that little calendar icon and nothing happens.

 

Now, I will share my UI page code... full disclosure, I got this far by using ChatGPT - It helps me be far more productive.  But, it doesn't know even close to everything and it is often wrong.  I've hit a wall with it and this.  

 

Here is the HTML section (I'm not even sure I need all this because clearly the modal is bringing up the new record form from the table... but I did what ChatGPT told me to do.)

<div id="calendar"></div>

<div id="myModal" class="modal">
  <div class="modal-content">
    <span class="close">&#215;</span>
    <h2>Create New Record</h2>
    <form id="recordForm">
      <label for="startDate">Start Date:</label>
      <input type="text" id="startDate" name="startDate" readonly="readonly"></input>

      <label for="description">Description:</label>
      <input type="text" id="description" name="description"></input>

      <label for="notes">Notes:</label>
      <textarea id="notes" name="notes"></textarea>

      <label for="driver">Driver:</label>
      <input type="text" id="driver" name="driver"></input>

      <button type="submit">Save</button>
    </form>
  </div>
</div>





<!-- Include the FullCalendar library -->
<script src="sys_attachment.do?sys_id=ae516fef1b536550cc11fee58d4bcb1c"></script>

 

And here is the client script portion:

 

document.addEventListener('DOMContentLoaded', function() {
  var calendarEl = document.getElementById('calendar');
  var calendar = new FullCalendar.Calendar(calendarEl, {
    headerToolbar: {
      left: 'prev,next today',
      center: 'title',
      right: 'dayGridMonth,timeGridWeek,timeGridDay'
    },
    initialView: 'dayGridMonth',
    events: function(info, successCallback, failureCallback) {
      // Fetch events from the 'u_logistics_shipping' table
      var gr = new GlideRecord('u_logistics_shipping');
      gr.query(function(response) {
        var events = [];
        while (gr.next()) {
          var event = {
            title: gr.getValue('u_description'),
            start: gr.getValue('u_start'),
            end: gr.getValue('u_end'),
            recordSysId: gr.getValue('sys_id') // Store the record's sys_id as a custom property
          };
          events.push(event);
        }
        successCallback(events);
      });
    },
    eventClick: function(info) {
      // Get the record sys_id from the clicked event's custom property
      var recordSysId = info.event.extendedProps.recordSysId;

      // Open the record in a new window or navigate to it
      var url = '/u_logistics_shipping.do?sys_id=' + recordSysId;
      window.open(url, '_blank'); // Open in a new window/tab
      // window.location.href = url; // Navigate to the record in the same window/tab
    },
    select: function(info) {
      // Create a new record with the selected start and end dates
      var gr = new GlideRecord('u_logistics_shipping');
      gr.initialize();
        gr.setValue('u_start', info.startStr);
		
      gr.setValue('u_end', info.endStr);
      // Set other properties of the record as needed

      // Insert the new record
      var sysId = gr.insert(function(response) {
        if (response && response.sys_id) {
          // Refresh the calendar to display the newly created event
          calendar.refetchEvents();
        }
      });
    },
    dateClick: function(info) {
      var clickedDate = info.dateStr;
      openModal(clickedDate);
		gr.setValue('u_start', clickedDate);
    }
  });

  function openModal(clickedDate) {
    var modal = new GlideModal('myModal'); // Replace 'myModal' with the ID of your modal element
    modal.setTitle('New Shipment');
    modal.setPreference('clickedDate', clickedDate);
    modal.setPreference('table', 'u_logistics_shipping');
    modal.setPreference('func', 'createNewRecord');
    modal.render();

    // Set the start date field value
    var startDateField = document.getElementById('startDate');
    startDateField.value = clickedDate;
	 // modal_form.setValue('u_start', startDateField.value);
alert(startDateField.value);
	  info.u_start = startDateField.value;
    // Initialize the date picker
   // $j(startDateField).datepicker();
  }

  calendar.render();
});

 

So, I would like your help solving the two problems:

1.  Auto fill the u_start field. (number 1 priority)

2. Fix the date picker (if that's even possible).

 

Thank you!

Daniel

1 ACCEPTED SOLUTION

Daniel Shock
Kilo Sage

Solved it.  I went with GlideModalForm instead and that worked...much better.  Here is the client script.

// Add event listener to wait for the content to be loaded
document.addEventListener('DOMContentLoaded', function() {

  // Get the calendar element
  var calendarEl = document.getElementById('calendar');

  // Initialize the FullCalendar
  var calendar = new FullCalendar.Calendar(calendarEl, {
    
    // Configure header toolbar
    headerToolbar: {
      left: 'prev,next today',
      center: 'title',
      right: 'dayGridMonth,timeGridWeek,timeGridDay'
    },

    // Set the initial view
    initialView: 'dayGridMonth',

    // Fetch events from the 'u_logistics_shipping' table
    events: function(info, successCallback, failureCallback) {
      var gr = new GlideRecord('u_logistics_shipping');
      gr.query(function(response) {
        var events = [];
        while (gr.next()) {
          var event = {
            title: gr.getValue('u_description'),
            start: gr.getValue('u_start'),
            end: gr.getValue('u_end'),
            recordSysId: gr.getValue('sys_id')
          };
          events.push(event);
        }
        // Pass events to the calendar
        successCallback(events);
      });
    },

    // Event handler for clicking on an event
    eventClick: function(info) {
      // Get the sys_id of the record from the clicked event
      var recordSysId = info.event.extendedProps.recordSysId;

      // Construct the URL and open it in a new window/tab
      var url = '/u_logistics_shipping.do?sys_id=' + recordSysId;
      window.open(url, '_blank');
    },

    // Event handler for selecting a date range
    select: function(info) {
      // Initialize a new record
      var gr = new GlideRecord('u_logistics_shipping');
      gr.initialize();
      gr.setValue('u_start', info.startStr);
      gr.setValue('u_end', info.endStr);

      // Insert the new record
      gr.insert(function(response) {
        if (response && response.sys_id) {
          // Refresh the calendar to display the new event
          calendar.refetchEvents();
        }
      });
    },

    // Event handler for clicking on a date
    dateClick: function(info) {
      // Open the modal with the clicked date
      openModal(info.dateStr);
    }
  });

  // Function to open the modal form
  function openModal(clickedDate) {
    // Create and configure the GlideModalForm
    var modalform = new GlideModalForm('Logistics Shipping', 'u_logistics_shipping');
    modalform.setPreference('sysparm_query', 'u_start=' + clickedDate);
    modalform.render();
  }

  // Render the calendar
  calendar.render();
});

View solution in original post

3 REPLIES 3

Daniel Shock
Kilo Sage

Solved it.  I went with GlideModalForm instead and that worked...much better.  Here is the client script.

// Add event listener to wait for the content to be loaded
document.addEventListener('DOMContentLoaded', function() {

  // Get the calendar element
  var calendarEl = document.getElementById('calendar');

  // Initialize the FullCalendar
  var calendar = new FullCalendar.Calendar(calendarEl, {
    
    // Configure header toolbar
    headerToolbar: {
      left: 'prev,next today',
      center: 'title',
      right: 'dayGridMonth,timeGridWeek,timeGridDay'
    },

    // Set the initial view
    initialView: 'dayGridMonth',

    // Fetch events from the 'u_logistics_shipping' table
    events: function(info, successCallback, failureCallback) {
      var gr = new GlideRecord('u_logistics_shipping');
      gr.query(function(response) {
        var events = [];
        while (gr.next()) {
          var event = {
            title: gr.getValue('u_description'),
            start: gr.getValue('u_start'),
            end: gr.getValue('u_end'),
            recordSysId: gr.getValue('sys_id')
          };
          events.push(event);
        }
        // Pass events to the calendar
        successCallback(events);
      });
    },

    // Event handler for clicking on an event
    eventClick: function(info) {
      // Get the sys_id of the record from the clicked event
      var recordSysId = info.event.extendedProps.recordSysId;

      // Construct the URL and open it in a new window/tab
      var url = '/u_logistics_shipping.do?sys_id=' + recordSysId;
      window.open(url, '_blank');
    },

    // Event handler for selecting a date range
    select: function(info) {
      // Initialize a new record
      var gr = new GlideRecord('u_logistics_shipping');
      gr.initialize();
      gr.setValue('u_start', info.startStr);
      gr.setValue('u_end', info.endStr);

      // Insert the new record
      gr.insert(function(response) {
        if (response && response.sys_id) {
          // Refresh the calendar to display the new event
          calendar.refetchEvents();
        }
      });
    },

    // Event handler for clicking on a date
    dateClick: function(info) {
      // Open the modal with the clicked date
      openModal(info.dateStr);
    }
  });

  // Function to open the modal form
  function openModal(clickedDate) {
    // Create and configure the GlideModalForm
    var modalform = new GlideModalForm('Logistics Shipping', 'u_logistics_shipping');
    modalform.setPreference('sysparm_query', 'u_start=' + clickedDate);
    modalform.render();
  }

  // Render the calendar
  calendar.render();
});

Afshin2
Tera Expert

Hello Daniel,

Thank you for sharing your insights.

I recently joined a project that utilizes fullCalendar version 4 in a custom widget. However, after upgrading the instance to Utah, we encountered some issues where certain functionality, buttons, and styles were missing. Since I'm not familiar with fullCalendar, I believe upgrading it to the latest version, preferably 6.8.1 or a newer release, would be a beneficial solution.

I was wondering if you could provide some details regarding the version of fullCalendar you utilized and the specific SN instance you have. Additionally, it would be helpful if you could explain how you integrated that particular version.

Thank you in advance for your assistance.

Regards: Afshin

Sorry it's taken me so long to answer you.  I've been out on vacation and work has piled up. 

 

I used ChatGPT to figure it out mostly.  I went to the website and downloaded the most recent library:

 

https://fullcalendar.io/docs/getting-started

 

Which is 6.1.8, I believe.

 

I attached the library file (index.global.min.js) to a script include.

 

The UI page HTML calls the script include from the HTML code with this line of code: 

<!-- Include the FullCalendar library -->
<script src="sys_attachment.do?sys_id=ae516fef1b536550cc11fee58d4bcb1c"></script>

Here is our servicenow version:

 

Build name: Tokyo
Build date: 05-15-2023_1941