Обновление объекта Salesforce данными, поступающими из сторонней библиотеки Javascript
Я новичок в разработке Salesforce и начал работать над своей первой сертификацией разработчика платформы SF, но я не новичок в разработке программного обеспечения, это были отношения любви и ненависти, которые продолжались последние 20 лет.
В любом случае, перейдем к делу. Сказав, что я новичок в разработке Salesforce, многие молодые люди, которые сегодня приступили к разработке Salesforce без предварительного опыта работы с другими платформами и средами, не чувствуют себя комфортно с терминальной консолью (вставьте здесь усмешку, эти дети умрут, ха-ха! ). В настоящее время я являюсь веб-разработчиком Full Stack, это звание, которое они назвали тому, кто знает серверный Javascript, а также клиентский Javascript, со знанием jQuery, CSS, HTML5, отзывчивых веб-приложений, Angular, React, хотя Я не тратил так много времени на Angular, React, так как я смог создать свою собственную структуру внешнего интерфейса с EJS + jQuery, но это для другого обсуждения (извините за сегвей), а затем интеграции с сервером, будь то Heroku, Digital Ocean, Nodejitsu, простой AWS, Kubernetes или что-то еще, а затем дополнить его знаниями о разных источниках данных; SQL (Oracle, Postges, Sybase, MySQL и т. Д.), NoSQL (MongoDB и т. Д.) Плюс новейшие прогрессивные веб-приложения. Ясно, что разработка программного обеспечения - это игра, в которой нужно адаптироваться или умереть. Прямо сейчас Javascript управляет почти всем в веб-разработке, превосходя Ruby On Rails, Java, PHP и так далее. Следовательно, имеет смысл, когда ведущая компания CRM адаптируется в виде веб-компонентов Lightning. Итак, я просто кратко расскажу о веб-компонентах Lightning и о том, как мы будем передавать данные в объекты Salesforce, используя Apex в качестве класса контроллера и веб-компонент Lightning, где будет инициализироваться и использоваться сторонняя библиотека Javascript.
Класс Apex
Когда я впервые увидел код Apex, он напомнил мне Java (черт возьми! Почему мы вернулись сюда?), Да, он очень похож на Java от объявлений классов, коллекций до аннотаций. Присутствуют даже концепции объектно-реляционного сопоставления J2EE или запах Enterprise Java Beans (EJB), это очевидно в настраиваемых объектах с окончанием * __ c. Следующим шагом я должен был прочитать документацию Salesforce Developer Experience или SFDX и установить Salesforce CLI, и это уже предполагает, что опыт работы с консолью терминала неизбежен, потому что как веб-разработчик Full Stack я также освоил несколько Unix и серверы Linux, где мы использовали для развертывания наших приложений, созданных Maven (в те дни), в различных вариантах Unix и Linux, на сервере не было графических пользовательских интерфейсов. Итак, как вы собираетесь развертывать приложения Salesforce без браузера или пользовательского интерфейса? Простой, SFDX с интерфейсом командной строки Salesforce. Потому что, когда вы регистрируетесь в изолированной программной среде разработчика в Salesforce, это, по сути, «организация», которая должна быть авторизована для разработки, и чтобы сделать это быстро, нужно ввести в консоли терминала команду, которая выглядит следующим образом:
$ sfdx:force:org <options here>
Итак, давайте теперь предположим, что у нас все правильно настроено и готово к написанию нашего класса Apex, и это выглядит примерно так:
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__c ORDER 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__c WHERE 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; } }
По сути, у нас есть класс контроллера Booking, который обновляет объект Booking__c. Функция updateBooking () будет вызываться из веб-компонента Lightning, который представляет собой код Javascript. Передача параметров проста, а привязка параметров проста, как вы можете видеть в: sfid, но, к сожалению, этот метод не упоминается ни в каких модулях trailhead (trailhead - это сайт обучения Salesforce) или каких-либо примерах документации.
Веб-компонент Lightning
Теперь, когда мы смогли создать наш класс Apex, пришло время создать наш веб-компонент Lightning. Веб-компонент Lightning на самом деле представляет собой ECMA-совместимый код Javascript, и если вы какое-то время занимались кодированием на Javascript, вам не составит труда изучить веб-компонент Lightning.
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 render if (this.fullCalendarJsInitialised) { return; } this.fullCalendarJsInitialised = true; // Executes all loadScript and loadStyle promises // and only resolves them once all promises are done let 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 configuration console.log({message: ‘Values’, values}); this.initialiseFullCalendarJs(values[4]); }) .catch(error => { // eslint-disable-next-line no-console console.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 today navLinks: true, // can click day/week names to navigate views editable: true, eventLimit: true, // allow “more” link when too many events events: 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 object this.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; } } }); } }
Теперь у нас есть веб-компонент Lightning, который импортирует библиотеку FullCalendarJS как стороннюю библиотеку Javascript. Эта библиотека была инициализирована данными событий через объект JSON bookingData, который будет записан в массив событий и передан как свойство события во время инициализации календаря, который будет служить сторонними данными, которые будут переданы обратно в Salesforce при их обновлении с помощью определенное действие, в нашем примере это воображаемый пользователь, который перетаскивал событие в календаре с одной даты на другую и обновляет эту дату в объекте Booking__c в классе Apex, это действие произойдет после того, как событие 'eventDrop' будет вызывается из FullCalendarJS, и он вызывает проводной метод updateBooking (подробнее о концепциях подключения см. в документации по веб-компоненту Salesforce Lightning). Даты из FullCalendarJS передаются в виде строк, а не как объект Javascript Date в класс Apex BookingController, потому что объект Apex Date и объект Javascript Date напрямую НЕСОВМЕСТИМЫ! Следовательно, если вы вернетесь к нашему коду BookingController, значения даты должны быть десериализованы с помощью JSON, чтобы он мог успешно обновить объект Booking__c с новыми датами. Итак, теперь у меня появилась идея для библиотеки AppExchange, API Lightning Date Wrapper, которую, я думаю, я могу взимать 1 доллар за загрузку / использование.
Вот и все! С удовольствием отвечу на любые вопросы из комментариев.