Tuesday 28 July 2020

ES6 features in Lightning Web Components Part 3 - Rest and Spread Operators

July 28, 2020 Posted by Sandeep No comments

Rest Operator
A Rest operator can be used in a function in which we are not sure about number of variables that have to be passed.
To make a parameter as a Rest parameter add three periods (...) before the parameter name.
As an example, we can create a function that can accept any number of parameters and find the sum of all the parameters.
import { LightningElement, track } from 'lwc';

export default class restsum extends LightningElement {
    connectedCallback(){
        console.log(this.sum(1,2,3,4,5,6));//Output is 21
    }
    //Method to find sum 
    //It can accept any number of parameters
   sum(...restParameters){
       return restParameters.reduce((a, b) => a + b, 0);
   }
}
The Rest parametes complement Higher Order Functions(Discussed in part 2 of this blog series) and can be used together for plethora of use cases.
The Rest operator can also be used to overload functions in Javascript.
For eg we can have a function that only adds 3 numbers.
import { LightningElement, track } from 'lwc';
export default class restsum extends LightningElement {
    connectedCallback(){
        let a = [1,2,3,4];
        console.log(this.sumFirstThree(...a));
        //Output would be 6 i.e. sum of first Three
    }
   sum(a,b,c){
       return a+b+c;
   }
}
Even if we add 4 or more elemts to the array, the function would only use the first 3 elements and find their sum.

Spread Operator
Unlike Rest Operator the spread operator 'spreads' or 'unpacks' collected element into single element. It also uses three periods (...) before the variable name. It can be used for various use cases like
1. Adding elements in between an array
let a = ['apple', 'orange', 'banana'];
let b = ['guava', ...a, 'strawberry'];
console.log(b);//[ "guava", "apple", "orange", "banana",  "strawberry"]
2. Copying Arrays
To understand the concept of copying arrays using spread operators consider two examples of copying arrays
Example 1:
let a = ['apple', 'orange', 'banana'];
let b = a;
b.push('blueberry');
console.log(b);//[ "apple", "orange", "banana", "blueberry" ]
console.log(a);//[ "apple", "orange", "banana", "blueberry" ]
 If you run the above code in your browser console or in LWC you would observe that both the variables a and b have the same 4 elements! Even though we just added the fourth value to array b. To avoid a situation like this we can use Spread Operator.
let a = ['apple', 'orange', 'banana'];
let b = [...a];
b.push('blueberry');
console.log(b);//[ "apple", "orange", "banana", "blueberry" ]
console.log(a);//[ "apple", "orange", "banana"]
As can be seen from the Ouput given in the comments now array b has the 4th element and array a retains its value and has the original 3 elements.

Saturday 14 March 2020

Create HTML elements in a Lightning Flow

March 14, 2020 Posted by Sandeep 1 comment
Flows are the most powerful point and click automation tool available on the Salesforce Platform. They can be used to perform actions in the Salesforce org or external systems. There are two types of flows:
1. Auto-launched flows
2. Screen flows
In this post we are going to discuss the latter. Screen flows come in very handy to create user forms that can take input from the user and perform operations based on these inputs. In some use cases we need to display certain data on a record page. While we can reference LWC and Aura components in a flow, this creates a dependency on a developer to debug issues or even make minor changes to the component.
If we will have a look at the Screen flow builder, we can see that there is just 1 output component and 23 input components!

The only component available for output is Display Text. While one might think that this component can only show Flow variables in plain text, turns out that this component can take in HTML tags and render HTML.
In our example we will create a component that will display all the contacts related to an Account, all without creating any Apex Class or Lightning component.
Step 1: Create an input variable of type Text that takes in the RecordId from the Account

Make sure that the 'Available for input' checkbox is selected.

Step 2: Use the 'Get Records' element to fetch the contacts. Make sure that in the filter condition the AccountId is equal to the RecordId variable created in the previous step
 Under the How to Store Record Data select 'Automatically store all fields' option or we can manually select the fields required on the table that we are creating

Step 3: You can use an online word to html convertor such as generate the html required to create. In our example we will be using data table from Lightning Design System, which will be responsive as well. The gotcha in this step is that you need to know what part of HTML is going to be repeated. We will use these inside the for loop element in the next step. More about this in later steps.

Step 4: We will create a text variable which will contain the HTML header tags before the repeating rows. The creation of variable should be as shown below
Since the header would remain constant we will add it to the Default value of our variable. You can see the default value code from here.

Step 5: Now time to create the logic for repeating rows, this is the data that we collected using Get Contacts action.
Add the Loop element on the screen.
In the collection variables select Get_Contacts.
Create a Loop variable called Contact that will iterate over each and every Contact record fetched by the Get Contacts element

Step 6: Create a new text variable called 'Row HTML'. This variable will store all the HTML that will be used to generate rows of each record in the table. The default value of this variable will be left as blank.

Step 7: We will add an assignment element on the screen called 'Create Row HTML' that will be used to add the row HTML for each and every record
We are using the Add operator so that every rows data is added to the RowHTML variable.The HTML code added in the value is
<td>
  <div class="slds-truncate">{!Contact.Name}</div>
</td>
<td>
  <div class="slds-truncate">{!Contact.Email}</div>
</td>
<td>
  <div class="slds-truncate">{!Contact.Fax}</div>
</td>
 In every div tag we are adding the Field that needs to be displayed in each and every column. Since we are using the Loop Variable Contact, this value will keep on changing as we iterate over records.

Step 8: Click on the Done button and connect the Loop Contacts with the assignment so that it works 'For Each Item'. Connect the Create Row HTML assignment to the loop to close off the loop. The flow should now look as shown below
 
Step 9:  Create a new Screen Flow. Deselect the 'Show Footer' checkbox. Drag and Drop the 'Display Text' element on the screen. In the insert resource section add the HTMLHeader and RowHTML variables. The screen element should look as shown:


Step 10: Connect the  Loop with the screen and save the flow. The flow should finally look as shown:

Click on the Debug button, enter an Account Id that has atleast 1 contact and verify if the flow created is working properly.

We can now add this flow on an account page or any other page as per our use case. The XML code for the above flow can be found here.

Leveraging the above example an admin can use a flow for countless more use cases and efficiently build HTML components that can be used throughout a Salesforce org.

   





Thursday 14 November 2019

Two way data binding in LWC

November 14, 2019 Posted by Sandeep 1 comment
One of the most commonly used feature when developing aura components was two way  data binding. All the fields displayed on a screen were related to a single JSON object and that JSON object was later used in a DML operation in an Apex class.



The code for above functionality is:

<aura:component >
    <aura:attribute name="myObject" type="Map" default="{}"/>
    <lightning:layout>
        <lightning:layoutItem size="6" padding="around-medium">
            <lightning:input name="textField" value="{!v.myObject.textField}" label="Text Field"/>
        </lightning:layoutItem>
        <lightning:layoutItem size="6" padding="around-medium">
            <lightning:input name="IntegerField" value="{!v.myObject.IntegerField}" type="number" label="Integer Field"/>
        </lightning:layoutItem>
    </lightning:layout>
    <div class="slds-p-around_medium">
        String  = {!v.myObject.textField}<br/>
        Integer = {!v.myObject.IntegerField}
    </div>
    
</aura:component>
The code does not require any Javascript logic and is quite handy in situations where data in fields had to be associated with a JSON object.

With LWC though, we have to manually bind fields to record changes in them. While this makes field binding logic more in line with other JS frameworks, for people who have been introduced to Javascript through Aura this change can be quite challenging.
A look into the LWC recipes library by salesforce, the example shown for data binding requires a developer to manually bind each and every field present on the UI using the change event handlers. While this would be manageable for a few fields.If there are a lot of fields on the UI that all are related to a JSON object. Writing checks for each and every field simply means a lot of redundant code and it is just not practical.

Enter data-* Attributes and dynamic JavaScript objects:
The data-* attributes are used to store custom data private to the page or application.
Have a look at this stack overflow thread in case you want to understand how dynamic objects are created in JavaScript. Using these two features we can build an object structure that is in line with Salesforce objects and can be directly sent to Apex for DML or any other operation that we wish to perform.

The LWC code replicating the above given functionality with minimal lines of code is:
<template>
    <lightning-card>
        <lightning-layout>
            <lightning-layout-item size="6" padding="around-medium">
                <lightning-input data-field="textField" label="Text Field" onchange={fieldChanged}></lightning-input>
            </lightning-layout-item>
            <lightning-layout-item size="6" padding="around-medium">
                <lightning-input data-field="IntegerField"  type="number" label="Integer Field" onchange={fieldChanged}></lightning-input>
            </lightning-layout-item>
        </lightning-layout>
        <div class="slds-p-around_medium">
            String  = {myObject.textField}<br/>
            Integer = {myObject.IntegerField}
        </div>
    </lightning-card>
</template>

If you will have a look at the lightning-input fields in the above code you will notice 2 things:
1. Both of them call the same on change event called fieldChanged
2. The data-field attribute should specify the key value for the JSON object(In case of Salesforce object we can name it as the field API name)
The Javascript logic for the web component is as follows:
import { LightningElement, track } from 'lwc';

export default class databinding extends LightningElement {
    @track myObject = {}
    fieldChanged(event){
        this.myObject[event.target.getAttribute('data-field')] = event.target.value;
    }
}
That's it! The one line written in the fieldChanged function will bind the fields with the myObject.
The above template can be leveraged to bind as many fields with a JSON object in Javascript.

The working example can be found here.


Sunday 29 September 2019

ES6 features in Lightning Web Components Part 2 - Arrow and Higher Order Functions

September 29, 2019 Posted by Sandeep No comments
In the second part of this series we will discuss about the Arrow functions. They were introduced in ES6 to allows us to write shorter function syntax.

Consider the below given function:
const myFunc = function() {
  const myVar = "returnValue";
  return myVar;
}
Instead of the above syntax we can use ES6 syntax as:
const myFunc = () => {
  const myVar = "returnValue";
  return myVar;
}
The arrow function syntax allows us to completely omit the return statement:
const myFunc = () => "value"
We can use arrow functions to write concise and small functions very clearly in LWC.

Higher Order Functions
By definition Higher Order functions are functions that accepts and/or returns another function.

1. Map Function

The map() method creates a new array with the results of calling a function for every array element.
The syntax for the method is:
array.map(function(currentValue, index, arr), thisValue)
  • currentValue (required): The value of the current element
  • index (optional): The array index of the current element
  • arr (optional): The array object the current element belongs to
  • thisValue (optional): Value to use as this when executing callback.
The below LWC code shows how we can square each and every element of an array:
import { LightningElement, track } from 'lwc';
export default class App extends LightningElement {
    connectedCallback(){
        let a = [1,2,3,4];
        a.map(this.findSquare);
    }
     findSquare(item){
        console.log(item*item);// 1,4,9,16
    }
}
We can shorten the above code further by using the arrow functions that we just learnt!
import { LightningElement, track } from 'lwc';
export default class App extends LightningElement {
    connectedCallback(){
        let a = [1,2,3,4];
        a.map(item => console.log(item*item));// 1,4,9,16
    }
}
2. Filter function

The filter() method creates a new array with all elements that pass the test implemented by the provided function.
The syntax for this method is:
array.filter(function(currentValue, index, arr), thisValue)
The arguments are similar to map function.
import { LightningElement, track } from 'lwc';
export default class App extends LightningElement {
    connectedCallback(){
        let arrayNumber = [2,5,67, 8, 90];
        const evenArray = arrayNumber.filter(item => item%2 === 0);
        console.log(evenArray); // 2,8,90
    }
}
3. Reduce function

The reduce() method reduces the array to a single value.
The reduce() method executes a provided function for each value of the array (from left-to-right).
The syntax for this function is:
array.reduce(function(total, currentValue, currentIndex, arr),initialValue)
  • total (required): The initialValue, or the previously returned value of the function
  • currentValue (required) : The value of the current element
  • currentIndex (optional) : The array index of the current element
  • arr (optional) : The array object the current element belongs to
  • initialValue (optional) : A value to be passed to the function as the initial value
import { LightningElement, track } from 'lwc';
export default class App extends LightningElement {
    connectedCallback(){
        let arr = [1, 2, 3, 4];
        let total = arr.reduce( (sum, current) => sum += current  ) ;
        console.log(total); // 10
    }
}

The code examples can be found here.  

Monday 2 September 2019

ES6 features in Lightning Web Components Part 1 - Variable Declarations

September 02, 2019 Posted by Sandeep , , , No comments
In December last year Salesforce announced to the world Lightning Web Components(LWC), a programming model that would make it easy for millions of JavaScript developers worldwide to code on the Lightning Platform. One of the main advantages of using LWC  is the support of ES6+ that would provide support for JavaScript features like classes, modules and import.

Like any excited developer I was inching to go through the documentation and see the capability of the framework.Salesforce documentation does a very good job to provide examples of creating numerous components on the Lightning Platform. Although while going through the documentation and examples, I came across various terms and bits of code that did not make much sense to me. A little more digging into these examples made me realise that some parts of code was using  ECMAScript 6 (or ES6) features that I rarely used while developing Aura Components.  Considering that LWC is the latest standard and are here to (hopefully :p) stay, I decided to understand the fundamentals of Modern JavaScript and ES6 Standards.

This series of posts will provide the foundation that a developer requires to understand modern Javascript standards and will also provide an introduction to new syntax and some awesome features to make out LWC code more modern, faster and more readable. Before we dive into the code of all the examples shown, I have tested all the code and it only requires LWC playground to compile.

Difference between var and let keywords

While both the keywords are used to declare variables in JavaScript, they behave quite differently. Have a look at the example below with var:
import { LightningElement, track } from 'lwc';
export default class VarLet extends LightningElement {
    connectedCallback(){
        var thisWillChange = 'String';
        var thisWillChange = 'Updated String';
        console.log(thisWillChange);
        // logs 'Updated String'
    }
}
In case you are not aware of what connectedCallback()  function does have a look at LWC documentation. While the problem shown above will be rarely faced in a small application, but as or code becomes larger(like it always does) we might accidentally override a  variable that was already being used.
Well this is not the only problem with 'var' keyword. We all love for loops (which we wont if we stick to these posts long enough!), if we declare the iterator as a var variable then it can be accessed outside the scope of that for loop. Have a look at the code snippet below and it's output
import { LightningElement, track } from 'lwc';
export default class VarFor extends LightningElement {
    connectedCallback(){
        for(var i=0; i<3; i ++){
            //loop logic here
        }
        console.log(i);
        //logs '3'
    }
}
We will try both the examples with let keyword instead.

Declaring the same variable with let keyword twice throws an error.
import { LightningElement, track } from 'lwc';
export default class LetOverride extends LightningElement {
    connectedCallback(){
        let thisWontChange = 'String';
        let thisWontChange = 'Updated String';
        //The above line will throw the error 
        //"Identifier 'thisWontChange' has already been declared (5:12)"
        console.log(thisWontChange);
    }
}
ReferenceError would occur if we try to access the iterating variable of a for loop if it is defined as a let variable. We will see the following output:

import { LightningElement, track } from 'lwc';
export default class LetFor extends LightningElement {
     connectedCallback(){
        for(let i=0; i<3; i ++){
            //loop logic here
        }
        console.log(i);
        //Throws a reference error that i is not defined 
    }
}

The const keyword

A variable assigned with const cannot be reassigned. In the below example reassigning the variable THIS_WONT_CHANGE gives an error.
import { LightningElement, track } from 'lwc';
export default class ConstEx1 extends LightningElement {
    connectedCallback(){
        const THIS_WONT_CHANGE = 'Sun rises in the east';
        THIS_WONT_CHANGE = 'Sun rises in the west';
        console.log(THIS_WONT_CHANGE);
        //Throws an error:
        //TypeError: Assignment to constant variable.
    }
}
As a best practice always declare constant variables as all uppercase letters.

Using const keyword with objects and arrays
There is one "gotcha" declaring objects and arrays as const. The const  keyword alone does not prevent  data from mutation. Which basically means that while we cannot completely reassign an object or an array but we can update the data inside the object or the array.
import { LightningElement, track } from 'lwc';
export default class ConstMutation extends LightningElement {
    connectedCallback(){
        const CONST_ARRAY = [1,2,3];
        //constArray = [2,3,4];
        //If above line is uncommented, it throws an error
        CONST_ARRAY[1] = 5;
        console.log(CONST_ARRAY);
        //logs [1,5,3]
    }
}
We can use the function Object.freeze to prevent a const keyword mutation.
import { LightningElement, track } from 'lwc';
export default class ConstMutation extends LightningElement {
    connectedCallback(){
        const CONST_ARRAY = [1,2,3];
        Object.freeze(CONST_ARRAY)
        CONST_ARRAY[1] = 5;
        console.log(CONST_ARRAY);
       //Throws a TypeError : Cannot assign to read only property 
      //'1' of object '[object Array]'
    }
}
In the next post I will cover arrow and Higher Order functions and how they can be implemented in Lightning Web Components.