Updating Salesforce Object with data coming from a third-party Javascript library

I’m new to Salesforce development and started working on my first SF platform developer certification but I’m not new to software development, it has been a love-hate relationship going on in the past 20 years.

Anyway, let’s get down to the business. Having said that I’m new Salesforce development, a lot of young folks today who went straight down to Salesforce development without prior experience from other platforms and environments aren’t comfortable with the terminal console (insert grin here, these kids gonna die haha!). Currently, I’m a Full Stack Web Developer, that’s the title they put on someone who knows server-side Javascript as well as client-side Javascript, with knowledge on jQuery, CSS, HTML5, Responsive Web Apps, Angular, React , though I didn’t spend so much time on Angular, React since I was able to build my own frontend framework with EJS + jQuery but that’s for another discussion (sorry for the segway) and then backend integration whether it’s Heroku, Digital Ocean, Nodejitsu, plain AWS, Kubernetes or whatever and then top it off with knowledge on different data sources; SQL (Oracle, Postges, Sybase, MySQL etc.), NoSQL (MongoDB etc.) plus the latest called Progressive Web Apps. Clearly, software development is an adapt-or-die game. Right now, Javascript rules almost everything in web development beating Ruby On Rails, Java, PHP and so forth. Therefore, it makes a lot of sense when a top CRM company will adapt in the form of Lightning Web Components. So I’ll just go through briefly on Lightning Web Components on how we will pass data to Salesforce Objects using Apex as a controller class and Lightning Web Component where the third-party Javascript library will be initialised and used.

The Apex Class

When I first saw an Apex code, it reminded me of Java(oh shit! Why are we back here?), yes, it resembles a lot like Java from class declarations, collections to annotations. Even J2EE’s object-relational mapping concepts or the stench of Enterprise Java Beans (EJBs) are there , it’s evident in the custom objects with *__c endings. Next step was I had to read through the Salesforce Developer Experience or SFDX documentation and installed the Salesforce CLI and that already suggests that an experience with the terminal console is imminent , because as a Full Stack Web Developer, I also got my hand in several Unix and Linux servers where we used to deploy our Maven-built (back in those days) apps in different flavors of Unix and Linux,there were no graphical user interfaces on the server. So how are you going to deploy Salesforce apps without a browser or UI? Simple, SFDX with Salesforce CLI. Because when you sign up for a developer’s sandbox in Salesforce it is basically an “org” that needs to be authorized for development and to be able to do that quickly is by typing a command that looks like this in the in the terminal console:

$ sfdx:force:org <options here>

So let us now assume we have everything properly set up and ready to write our Apex class and it goes a little something like this:

public with sharing class BookingController {@AuraEnabled(Cacheable=true)public static Booking__c[] getAllBookings () { return [SELECT Name, Account__c, Start_Date__c, End_Date__c FROM  Booking__cORDER BY Name LIMIT 10];}@AuraEnabled
public static void updateBooking(String name, String sfid, String startDate, String endDate){
try {Booking__c booking = [SELECT Id, Name, Account__c, Start_Date__c, End_Date__c FROM Booking__cWHERE Id = :sfid LIMIT 1 FOR UPDATE];Datetime sDatestr = (Datetime)JSON.deserialize(‘“‘ + startDate + ‘“‘, Datetime.class);Datetime eDatestr = (Datetime)JSON.deserialize(‘“‘ + endDate + ‘“‘, Datetime.class);Datetime sysDate = System.now();booking.Start_Date__c = sDatestr;booking.End_Date__c = eDatestr;update booking;} catch (Exception e) {System.debug(‘An error has occurred: ‘ + e.getMessage());} finally { } return; }}

Basically, we have a Booking controller class that updates the Booking__c object. The updateBooking() function will be called be from the Lightning Web Component which is a Javascript code. Passing the parameters is straightforward and binding the parameters is simple as well as you can see in the :sfid but unfortunately, this technique is not mentioned in any trailhead modules (trailhead is a Salesforce training site) or any example documentations.

The Lightning Web Component

Now that we were able to build our Apex class, it’s time to create our Lightning Web Component. Lightning Web Component is actually an ECMA-compatible Javascript code and if you have been coding in Javascript for a while it shouldn’t be hard to learn Lightning Web Component

import { LightningElement, track, wire, api } from ‘lwc’;
import { loadScript, loadStyle } from ‘lightning/platformResourceLoader’;
import FullCalendarJS from ‘@salesforce/resourceUrl/FullCalendarJS’;
import getAllBookings from ‘@salesforce/apex/BookingController.getAllBookings’;
import updateBooking from ‘@salesforce/apex/BookingController.updateBooking’;
import { refreshApex } from ‘@salesforce/apex’;
const FIELDS = [SERVICE_NAME, BOOKING_ID];/*** FullCalendarJs* @description Full Calendar JS — Lightning Web Components*/export default class FullCalendarJs extends LightningElement {
@api recordId;
@track error;
@track sfid;
@track startDate;
@track endDate;
@track name;
@wire (getAllBookings) bookings;
@wire (updateBooking, {name: ‘$name’, sfid:’$sfid’, startDate: ‘$startDate’, endDate: ‘$endDate’}) updateBooking;
//@track bookings;fullCalendarJsInitialised = false;/*** @description Standard lifecyle method ‘renderedCallback’* Ensures that the page loads and renders the* container before doing anything else*/renderedCallback() {// Performs this operation only on first renderif (this.fullCalendarJsInitialised) { return;}this.fullCalendarJsInitialised = true;// Executes all loadScript and loadStyle promises// and only resolves them once all promises are donelet bookingPromise = Promise.resolve(this.bookings.data);Promise.all([bookingPromise,loadScript(this, FullCalendarJS + ‘/jquery.min.js’),
loadScript(this, FullCalendarJS + ‘/moment.min.js’),
loadScript(this, FullCalendarJS + ‘/fullcalendar.min.js’),
loadStyle(this, FullCalendarJS + ‘/fullcalendar.min.css’),
]).then((values) => {// Initialise the calendar configurationconsole.log({message: ‘Values’, values});this.initialiseFullCalendarJs(values[4]);}).catch(error => {// eslint-disable-next-line no-consoleconsole.error({message: ‘Error occured on FullCalendarJS’,error});})}/*** @description Initialise the calendar configuration* This is where we configure the available options for the calendar.* This is also where we load the Events data.*/initialiseFullCalendarJs(bookings) {const ele = this.template.querySelector(‘div.fullcalendarjs’);/* $(‘.cal-draggable’).draggable({revert: true,revertDuration: 0}) */const bookingData = this.bookings.data;let dataObj = {};let events = [];bookingData.forEach(element => {dataObj.title = element.Name;dataObj.sfid = element.Id;dataObj.start = element.Start_Date__c;dataObj.end = element.End_Date__c;dataObj.url = ‘/’ + element.Id;dataObj.account__c = element.Account__c;events.push(dataObj);dataObj = {};});// eslint-disable-next-line no-undef$(ele).fullCalendar({header: {left: ‘prev,next today’,center: ‘title’,right: ‘month,basicWeek,basicDay’},//defaultDate: ‘2019–01–12’,droppable: true,defaultDate: new Date(), // default day is todaynavLinks: true, // can click day/week names to navigate viewseditable: true,eventLimit: true, // allow “more” link when too many eventsevents: events,eventDrop: (event, delta, revertFunc)=>{alert(event.title + “ — “ + event.sfid + “ was dropped on “ + event.start);if (!confirm(“Are you sure about this change?”)) {revertFunc();} else {//update the booking objectthis.sfid = event.sfid;this.startDate = event.start.format();this.endDate = event.end.format();this.name = event.account__c;console.log(‘Passing: ‘, this.name + ‘; ‘ + this.sfid + ‘; ‘ + this.startDate + ‘; ‘ + this.endDate);updateBooking({name: this.name, sfid: this.sfid, startDate: this.startDate, endDate: this.endDate}).then((data)=>{console.log (‘Result affected: ‘, data);return refreshApex(this.bookings)}).catch((error)=>{console.log(‘Error received: ‘, error.errorCode + ‘ ‘ + error.body.message);});//let result = this.updateBooking.data;}}});}}

Now, we have a Lightning Web Component which imports a FullCalendarJS library as the 3rd party Javascript library. This library was initialised with an events data through the bookingData JSON object which will be written to the events array and passed as an event property during the calendar initialisation that will serve as a the 3rd party data to be passed back to Salesforce when it’s updated by a certain action, in our example, it’s an imaginary user who dragged and dropped an event in the calendar from one date to another and updates that date to the Booking__c object in the Apex class, this action will happen once the ‘eventDrop’ event is called from the FullCalendarJS and it will call the wired method ‘updateBooking’ (more on wiring concepts in the Salesforce Lightning Web Component documentation). The dates from the FullCalendarJS are passed as strings and not as Javascript Date object to the Apex BookingController class because the Apex Date object and the Javascript Date Object are directly INCOMPATIBLE! Hence, if you go back to our BookingController code the date values has to be deserialized with JSON so that it can update successfully the Booking__c object with new dates. So now I got an idea for an AppExchange library, Lightning Date Wrapper API which I think I can charge $1 per download/use.

That’s it! Happy to answer any questions from the comments.




Developer of really cool apps in RUST and SLINT, Sketcher wannabe, Mercedes-Benz fanatic, SWAG Equities Trader, Certified Securities Representative

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Spatial Audio for Speaker Connected Devices

How to add a flashing border to CardView

The Delivery Manager Role — It’s Totally a Thing

Raspberry Pi GPIO in Golang and C — RGB LED

Reduce Cost and Increase Productivity with Value Added IT Services from buzinessware — {link} -

Resetting MySQL(Version 8) Password in Ubuntu

Using ChartMuseum as a chart repository for helm

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Jared Odulio

Jared Odulio

Developer of really cool apps in RUST and SLINT, Sketcher wannabe, Mercedes-Benz fanatic, SWAG Equities Trader, Certified Securities Representative

More from Medium

How to create the LWC Multi Select Combobox that Salesforce is still missing

Who would rather use a Lightning Dual Listbox instead of a Multi-Select Combobox?

Salesforce: Core Modules & What They Do

API Prototyping for Salesforce with Postman

Steps to create LWC Component