How to choose the best cloud platform for AI
Explore a strategy that shows you how to choose a cloud platform for your AI goals. Use Avenga’s Cloud Companion to speed up your decision-making.
I’ve been diving deep into migration from Aura to Lightning Web Components for quite some time now. When preparing for a workshop, to demonstrate how this can be done in action, I opted for the Aura component described in my article, which was used to build a simple employee list application using the standard lightning:datatable component from the Lightning Aura Framework. Since this standard component is also available for use in the Lightning Web Components Framework, I decided to prepare a workshop where the main task was to clone that application using an Aura component and replace the SimpleEmployeeList aura component with the SimpleEmployees Lightning Web Component counterpart. Also, I offered an additional task to clone another advanced application and replace a reference to another DataTable Aura component with the Lightning Web Component counterpart. Here, I’ll present a plan on how this migration can be performed with video screenshots of the most important steps.
The workshop task was to clone the SimpleDataApp and replace the SimpleEmployeeList Aura Component with the SimpleEmployees Lightning Web Component counterpart.
bdovhan/SimpleDataTableApp
application implemented using the Lightning Aura Framework.D:/Git/AuraToLWCWorkshop
.SimpleDataTable/readme.md
Start.bat
(would work for Windows; need to implement .sh correspondent file for Mac).SimpleDataApp.app
is opened.SimpleDataTableApp Folder
, as a project in Visual Studio Code.SimpleDataTableApp
either in VS by menu item or by code, or in the Developer Console. Call it SimpleAppUsesLWC.
If any component or app is created outside of the VS Code, use a retrieve menu item or command sfdx
force:source:retrieve -m AuraDefinitionBundle
to see that component or app inside the VS Code. SimpleDataTableApp App
to SimpleAppUsesLWC
. simpleEmployees
Lightning Web component. You may copy to it the commented code from SimpleEmployeeList
.simpleTable
Lightning Web component. You may copy to it the commented code from SimpleDataTable
.Id
“ for keyField
value) and standard provider references “!v
” and “!c
” from the commented code.kebab-cased
; add closing tags. The inner content of the html file of the component should look like the following:
<lightning-datatable data={data} columns={columns} key-field="id" hide-checkbox-column onsort={updateColumnSorting}> </lightning-datatable>
simpleTable.js
and declare data
and columns
properties there and the updateColumnSorting
method. Add track
to imports. Now simpleTable.js
should look like the following:
import { LightningElement, track } from 'lwc'; export default class SimpleTable extends LightningElement { @track data; @track columns; updateColumnSorting() {} }
'@salesforce/apex/SimpleDataTableController.getColumnsAndData '
simpleTable.js
should look like:
import { LightningElement, track } from 'lwc'; import getColumnsAndData from '@salesforce/apex/SimpleDataTableController.getColumnsAndData'; export default class SimpleTable extends LightningElement { @track data; @track columns; updateColumnSorting() {} }
sfdx force:source:deploy -m LightningComponentBundle
getColumnsAndData
.sObjectName
, sObjectFieldsNames
, whereClause into the promise initializer.replace component.get('v.
with this ..
sObjectName
, sObjectFieldsNames
, whereClause
, and import the api
modulethen
callback, to process a successful execution.@track error
; to the Javascript module. <template if:true={error}>
<template if:true={error.body}>
{error.body.message}
</template>
</template>
Now the list of attributes in it should look like the following:
@api sObjectName;
@api sObjectFieldsNames;
@api whereClause;
@track data;
@track columns;
@track error;
The connected callback function should look like this:
connectedCallback() {
getColumnsAndData({
sObjectName: this.sObjectName,
sObjectFieldsNames: this.sObjectFieldsNames,
whereClause: this.whereClause
}).then(result=>{
this.data = result.data;
this.columns = result.columns;
}).catch(error=>{
this.error = error;
});
}
kebab-cased
. Add closing tags. <c-simple-table s-object-name="Contact"
s-object-fields-names="FirstName,LastName,BirthDate,HireDate__c,Branch__c,Position__c,Email,Phone"
where-clause="RecordType.Name = 'Employee'">
</c-simple-table>
simpleEmployees
component inside of the SimpleAppUsesLWC
. The inner content of the SimpleAppUsesLWC
should look like:
<c:FakeOpportunityData/>
<c:simpleEmployees/>
<c:simpleTable sObjectName="Contact1"
sObjectFieldsNames="FirstName,LastName,BirthDate,HireDate__c,Branch__c,Position__c,Email,Phone"
whereClause="RecordType.Name = 'Employee'"/>
simpleTable.js
to transform the string value into an array and fix one of the null pointer errors. connectedCallback() {
getColumnsAndData({
sObjectName: this.sObjectName,
sObjectFieldsNames: this.sObjectFieldsNames.split(','),
whereClause: this.whereClause
}).then(result=>{
this.data = result.data;
this.columns = result.columns;
}).catch(error=>{
this.error = error;
});
}
SchemaProvider
class before line #6.
if ( Type.forName(token) == null ) {
throw new CustomException(token + ' is not valid SObject name');
}
And introduce an inner CustomException
class at the bottom of the class
public class CustomException extends Exception {}
SimpleDataTableController
lines 41 and 43-45, and see that the unhandled exceptions result in non-readable errors. Notice the non-readable exception and then revert change in the SimpleDataTableController
.updateColumnSorting
, sortData
and sortBy
from SimpleDataTableHelper.js
into simpleTable.js
and then comment them out.function
keyword and colon from the sortData
and sortBy
function definitions.event
by e
, then replace getSource()
by srcElement
, and remove set("v.
and the corresponding closing parenthesis. Also replace the comma by an assignment operator.getParam('
with detail.
and remove the corresponding closing parenthesis.helper
with this
and replace the cmp
param with e.srcElement.
sortBy
code, as it contains a valid LWC code and doesn’t have to be converted.sortData
, replace cmp
with src
, and replace get("v.data")
with JSON.parse(JSON.stringify(src.data))
and cmp.set("v.data"
, with src.data =
and remove the corresponding closing parenthesis.updateColumnSorting(e) {
e.srcElement.sortedBy = e.detail.fieldName;
e.srcElement.sortedDirection = e.detail.sortDirection;
this.sortData(e.srcElement, e.detail.fieldName, e.detail.sortDirection);
}
sortData(src, fieldName, sortDirection) {
/// src = equivalent to event.getSource()
var data = JSON.parse(JSON.stringify(src.data));
var reverse = sortDirection !== 'asc';
//sorts the rows based on the column header that's clicked
var primer = (data && data.length && data[0].Origin) ? (x, field)=>x.Origin[field] : null;
data.sort(this.sortBy(fieldName, reverse, primer));
src.data = data;
}
sortBy(field, reverse, primer) {
var key = primer ?
function(x) {return primer(x, field)} :
function(x) {return x[field]};
//checks if the two rows should switch places
reverse = !reverse ? 1 : -1;
return function (a, b) {
return a = key(a), b = key(b), reverse * ((a > b) - (b > a));
}
}
Listing of code inside simpleDataTableWiredFunction.html
<template>
<template if:true={error}>
<template if:true={error.body}>
{error.body.message}
</template>
</template>
<lightning-datatable data={data} columns={columns} key-field="id" hide-checkbox-column
onsort={updateColumnSorting}></lightning-datatable>
<lightning-datatable data={data} columns={columns} key-field="id" hide-checkbox-column
onsort={updateColumnSorting}></lightning-datatable>
</template>
Listing of code inside simpleDataTableWiredProperty.js
import { LightningElement, track, api, wire } from 'lwc';
import getColumnsAndData from '@salesforce/apex/SimpleDataTableController.getColumnsAndData';
import {copy} from 'c/copy';
export default class SimpleDataTableWiredFunction extends LightningElement {
@api sObjectName;
@track sObjectFieldsNamesArray;
get sObjectFieldsNames() {
return this.sObjectFieldsNamesArray;
}
@api
set sObjectFieldsNames(value) {
this.sObjectFieldsNamesArray = value.split(',');
}
@api whereClause;
@track data;
@track columns;
@track error;
@wire(getColumnsAndData, {
sObjectName: '$sObjectName', sObjectFieldsNames: '$sObjectFieldsNames'
, whereClause: '$whereClause'
})
wiredGet({ error, data }) {
if (data) {
this.data = data.data;
this.columns = data.columns;
this.error = undefined;
} else if (error) {
this.error = error;
this.data = null;
this.columns = null;
}
}
....
}
Note that in this case we have defined a private internal property to store fields as an array, and in public property setter we split the string value provided by a comma.
Listing of code inside simpleDataTableWiredProperty.html
<template>
<template if:true={columnsAndData.error}>
<template if:true={columnsAndData.error.body}>
{error.body.message}
</template>
</template>
<h1>Wired Property version</h1>
<template if:true={columnsAndData.data}>
<lightning-datatable data={columnsAndData.data.data} columns={columnsAndData.data.columns} key-field="id"
hide-checkbox-column onsort={updateColumnSorting}></lightning-datatable>
</template>
</template>
Listing of code inside simpleDataTableWiredProperty.js
import { LightningElement, track, api, wire } from 'lwc';
import getColumnsAndData from '@salesforce/apex/SimpleDataTableController.getColumnsAndData';
import {copy} from 'c/copy';
export default class SimpleDataTableWiredProperty extends LightningElement {
@api sObjectName;
@track sObjectFieldsNamesArray;
get sObjectFieldsNames() {
return this.sObjectFieldsNamesArray;
}
@api
set sObjectFieldsNames(value) {
this.sObjectFieldsNamesArray = value.split(',');
}
@api whereClause;
@wire(getColumnsAndData, {
sObjectName: '$sObjectName', sObjectFieldsNames: '$sObjectFieldsNames'
, whereClause: '$whereClause'
})
columnsAndData;
...
}
Note that in this case we also have defined the same private internal property to store fields as array declared for the wired function example, however, the code assigning value to the property is much shorter.
Listing of file dataTableLWC.html
<template>
<template if:true={error}>
<template if:true={error.body}>
{error.body.message}
</template>
</template>
<lightning-datatable data={data} columns={columns} key-field="id" sorted-by={sortedBy}
sorted-direction={sortDirection} hide-checkbox-column onsort={updateColumnSorting}></lightning-datatable>
</template>
Listing of file dataTableLWC.js
import { api } from 'lwc';
import getColumnsAndData from '@salesforce/apex/DataTableController.getColumnsAndData';
import SimpleDataTableLWC from 'c/simpleDataTableLWC';
export default class DataTableLWC extends SimpleDataTableLWC {
@api overrides;
@api valueModifiers;
connectedCallback() {
getColumnsAndData({ sObjectName:this.sObjectName, sObjectFieldsNames:this.sObjectFieldsNames.split(',')
, whereClause: this.whereClause, overrides: JSON.parse(this.overrides.replace(/'/g, '"'))
, valueModifiers: JSON.parse(this.valueModifiers.replace(/'/g, '"')) })
.then(result=>{
this.data = result.data;
this.columns = result.columns;
}).catch(error => {
this.error = error;
});
}
}
Note that we are able to extend not only standard components but also custom components in order to use inheritance to reduce code duplication. Otherwise, we might end up with dataTableLWC javascript code almost completely duplicating simpleDataTableLWC javascript code.
Also, we have defined two public properties with @api decorator.
Run ./finish.bat.
See this in action in the video screenshot
In my case, I had already pulled and committed all my changes. So pull command didn’t find any more changed files in the case shown in video screenshot.
Salesforce workshops are a great way to explore new features, develop your skills and share personal experience with the tech community, whether you attend or organise one. During my last workshop I demonstrated migration from Aura to Lightning Web Components in action. Attendees practiced cloning the sample project build on Aura Framework and replacing the sample Aura Component with the Lightning Web Component counterpart.
Lightning Web Components help Salesforce Developers to follow the latest Javascript code standards. Every Salesforce developer should get to know the new features provided by Salesforce and suggest the best appropriate development option to customers.
* US and Canada, exceptions apply
Ready to innovate your business?
We are! Let’s kick-off our journey to success!