Post 4 – Customizing Salesforce with Lightning Aura Components Series

This will be the fourth of a series of posts I will be doing over the next few weeks. This particular post will cover working with the Record Form Base Lightning Component. The series will all lead up to the introduction of my new course titled, “Customizing Salesforce with Lightning Aura Components” from Pluralsight. This course is a total re-write of my most popular course, “Customizing Salesforce with Lightning Components: Getting Started“, which was released back in early 2017. It will focus on using the new modern toolset that Salesforce offers as part of Salesforce DX.

Working with Record Forms

The recordEditForm and recordViewForm components have been around for a while, but the recordForm component was introduced in Summer 18 and was a big improvement. In fact, I was so impressed with this component, I wrote about it on this blog.

The recordForm component represents the best of two other components and essentially merges them into one. This means you will need to write less JavaScript code in the form of handlers, such as onload and onsubmit because the new component will handle these automatically.

Along with less markup, since you will not have to use lightning:input or lightning:output, along with cancel and submit buttons. They are provided for you automatically. And finally, the recordForm component is exposable to more platforms, which at this time includes Lightning Experience, Lightning Communities, Salesforce Mobile App, along with Lightning Out combined with Visualforce.

And the Drawbacks? Well, it is slightly less flexible and as of now, there is a known issue involving validation that I hope you consider voting for (since that is the only way Salesforce will fix it).

Creating a New Quick Case Component

In this section, I will show you how to build a component that let’s users quickly create a new case. The end result will be a component like this:

Quick Case Create Component
Quick Case Create Component

This component will use the recordForm base lightning component. Here is the code for the markup:

<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,force:lightningQuickAction" 
                            access="global"
>
    <aura:attribute name="fields" type="String[]" default="['Status','AccountId',
                                    'ContactId','Origin','Type','Reason','Subject']" />
    <aura:attribute name="reqFields" type="String[]" default="['Origin','Status']" />
    <aura:attribute name="recordId" type="String"/>
    <lightning:notificationsLibrary aura:id="notifLib"/>

    <lightning:card iconName="standard:case" title="Quick Case Create" >
        <p class="slds-p-horizontal_small">
            <lightning:recordForm objectApiName="Case" 
                          fields="{!v.fields}" 
                          onsuccess="{!c.handleSuccess}"  />
        </p>
    </lightning:card>	
</aura:component>	

And here is the code for the client-side controller. Note that it includes a commented method that would handle validation, since the component unfortunately does not do this (at this time – refer to issue above). I don’t really consider this a workaround, since the whole purpose of the component was to eliminate the need for the additional code. I personally think Salesforce needs to fix it, and hope you agree.

({
    handleSuccess : function(cmp, event, helper) {
           cmp.find('notifLib').showToast({
            "variant": "success",
            "title": "Case Created",
            "message": "Record ID: " + event.getParam("id")
        });
    }
    // },
    // handleValidation : function(cmp, event, helper) {
    //     // NOTE: This method will handle validation if you specify which field to check for specifically, which is 
    //     //  not a good workaround since the component should handle this for you without the need to write
    //     //  all this unecessary code (especially since the whole point of the component is to lessen the
    //     //  amount of code that needs to be written). That is why it was not mentioned in the actual course.
    //     var evtFields = event.getParam("fields");
    //     var reqField = 'Origin';
    //     if (evtFields.hasOwnProperty(reqField)) {
    //         event.preventDefault();  //Stops the record from being created
    //         cmp.find('notifLib').showToast({
    //             "variant": "error",
    //             "header": "Error was encountered",
    //             "message": "The following field is required: " + reqField
    //         });
    //     } 
        

})

The code includes the notifications base lightning component. This is used to alert the user with a toast message when the case was added successfully.

Creating Quick Actions

In addition to including this component on the Sales Home page, I exposed it as a quick action and then created a global action using the following steps in Setup.

  1. In Quick Find, type “global” and select Global Actions.
  2. Click New Action.
  3. Select “Lightning Component” as the Action Type.
  4. Select the quickCase component from the drop down list.
  5. Enter a label as “Quick Case Create” and tab to next line.
  6. Click Save to Finish.

After creating the global action, you still need to add the new action to the Publishers layout, which you do using the following steps:

  1. In Quick Find, type “Publisher” and select Publisher Layout.
  2. Click Edit to modify the default layout.
  3. Select “Mobile and Quick Actions”.
  4. Scroll down to the section for Salesforce Mobile and click the override the predefined actions link.
  5. Drag the Quick Case Create action onto the section.
  6. Click Save to finish.

In the next and final post, I will go over the newly redesigned Salesforce Mobile App.

Post 3 – Customizing Salesforce with Lightning Aura Components Series

This will be the third of a series of posts I will be doing over the next few weeks. This particular post will cover working with Salesforce Data. The series will all lead up to the introduction of my new course titled, “Customizing Salesforce with Lightning Aura Components” from Pluralsight. This course is a total re-write of my most popular course, “Customizing Salesforce with Lightning Components: Getting Started“, which was released back in 2017. It will focus on using the new modern toolset that Salesforce offers as part of Salesforce DX.

Working with Controllers

In the last post, I walked you through creating the updateCellNumber Aura component in Visual Studio Code. I also stepped you through how to add a design file so that the placeholder value was easily modifiable in Lightning App Builder.

So far this component will only show a windows alert when the submit button is pressed. I am going to show you how to change that and have it update the Salesforce database instead.

Lightning Components have two ways of dealing with Salesforce data:

  1. Using the Lightning Data Service
  2. Using Apex

In this post, I will only covering the second method of using Apex to write server-side code.

Working with Apex and DML

Apex is strongly-typed object-oriented proprietary language developed by Salesforce. Since Salesforce is a multi-tenanted environment, Apex is subject to limits.

DML or Data Manipulation Language is what Salesforce uses to insert, update or delete a Salesforce record. To change the updateCellNumber component so that it writes to the Salesforce database, I will need to add a Class that uses both Apex and DML. The class will be named updateCellNumberApex (so that it is not named the same as the client-side JavaScript controller). Any server-side methods used by Lightning components must have the @AuraEnabled annotation. They also must be public and static. The code for the class will be as follows:

public with sharing class updateCellNumberApex {
    @AuraEnabled()
    public static void CellNumberUpdate(String cellNumber) {
        List<User> users = [SELECT MobilePhone FROM User where 
                            Id =: UserInfo.getUserId()];
        
        if ( users.size() > 0 ) {
            users[0].MobilePhone = cellNumber;
            update users;
        }
    }
}

This code also uses a SOQL or Structured Object Query Language statement to select the MobilePhone number for the logged in user.

Once the class has been added, I will need to modify the component markup for updateCellNumber so that it is linked to this class. I do that by adding the following attribute to the aura:component tag, like this:

<aura:component controller="UpdateCellNumberApex"....

I will then need to switch to the client-side JavaScript controller and start by removing the code that produced a windows alert and replace it with the following:

var cellNumber = cmp.find("phone").get("v.value");
var action = cmp.get("c.CellNumberUpdate");
action.setParams({ "cellNumber" : cellNumber });
action.setCallback(this, function(response) {
    var state = response.getState();
    if (state === "SUCCESS") {
         alert(state);
     }
});
$A.enqueueAction(action);

Creating a New Open Cases Component

This component will display a list of open cases and will be named openCases. The final component will look like the following:

Open Cases Configureable Component
Open Cases Configureable Component

This Aura component will utilize the lightning:datatable base lightning component. Here is the code for the component markup:

<aura:component controller="getOpenCasesApex" implements="force:appHostable,flexipage:availableForAllPageTypes" access="global">
    <!-- attributes -->
    <aura:attribute name="caseList" type="Object"/>
    <aura:attribute name="columns" type="List"/>
    <aura:attribute name="numRecords" type="Integer" default="10" />

    <!-- handlers-->
    <aura:handler name="init" value="{! this }" action="{! c.init }"/>

    <lightning:card title="Open Cases">
        <lightning:datatable
                keyField="id"
                data="{! v.caseList }"
                columns="{! v.columns }"
                hideCheckboxColumn="true"/>
    </lightning:card>

</aura:component>	

And here is the JavaScript for the client-side controller:

({
    init : function(cmp, event, helper) {
        var numRecords = cmp.get("v.numRecords")

        cmp.set('v.columns', [
            {label: 'Subject', fieldName: 'linkName', type: 'url',
                typeAttributes: {label: {fieldName: 'Subject'}, target: '_self'}},
            {label: 'Type', fieldName: 'Type', type: 'text'},
            {label: 'Reason', fieldName: 'Reason', type: 'text'},
            {label: 'Status', fieldName: 'Status', type: 'text'},
        ]);

        var action = cmp.get("c.getOpenCases");
        action.setParams({"numRecords" : numRecords });
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                var records = response.getReturnValue();
                records.forEach(function(record){
                    record.linkName = '/' + record.Id;
                });
                cmp.set('v.caseList', records)
            }
        });
        $A.enqueueAction(action);
    }

})

The first part of this code is used to define the columns that will be used in the datatable. Notice that the first one is of the type url and that it has an additional definition for the typeAttributes. This is because this column will not only display the case subject, but will include a link to the case detail record.

The callback function will get whatever records are returned and then loop through those records and set the linkName so that it references the Cases record Id.

This component will utilize an Apex controller named getOpenCasesApex. It includes code needed to check for the appropriate FLS and CRUD level security. It also includes cacheable=true for the @AuraEnabled annotation in order to take advantage of caching for performance.

public with sharing class getOpenCasesApex {
    @AuraEnabled(cacheable=true)
    public static List<Case> getOpenCases(Integer numRecords) {
        // Code needed to check for proper access
        String [] caseFields = new String[] {'Id','Type','Reason','Subject','Status'};

        Map<String,Schema.SObjectField> caseMap = Schema.SObjectType.Case.fields.getMap();
        for (String fieldToCheck : caseFields) {
            if( !caseMap.get(fieldToCheck).getDescribe().isAccessible()) {
                throw new System.NoAccessException();
            }
        }

        List<Case> caseList = [SELECT Id,Type,Reason,Subject,Status FROM Case
        WHERE IsClosed = false
        LIMIT : numRecords];

        return caseList;
    }

}

And finally, it includes a numRecords input parameter, which is passed in form the value set when the component is configured in Lightning App Builder. The associated design file for this component is as follows:

<design:component label="Configurable Open Cases Component">
    <design:Attribute name="numRecords" label="Number of Records Returned" placeholder="10" />
</design:component>

In the next post, I will go over how to design components that do not require an Apex controller.

New Upcoming Pluralsight Course on Customizing Salesforce with Lightning Aura Components

I am VERY happy to announce that I am very close to releasing a new Pluralsight course called “Customizing Salesforce with Lightning Aura Components”. Well, kind of a new course.

Upcoming New Pluralsight Course

It is a total re-write of my most popular course (so far), “Customizing Salesforce with Lightning Components: Getting Started“, which was released back in 2017. That was right before Salesforce DX was released and all the other modern developer tools that Salesforce now promotes (for very good reasons).

In this course, all those great shiny new tools will be used to build very simple Aura Lightning Components, as they are now called. The original course used the online Developer Console, which is what Trailhead uses in all their content about Aura Components. On Trailhead, the new tools are only used for Lightning Web Components.

So, if you want to learn about building Aura Components, while also embracing the new modern toolset, this course is perfect for you. And if you want to learn about Lightning Web Components (LWC’s), then you can check out the “Building Your First Lightning Web Component (LWC) for Salesforce” course that I released earlier this year.

Both courses use the new tools, like:

Salesforce DX

Salesforce Command Line Interface

Salesforce Extensions for Visual Studio Code

Starting next week, I will be releasing a series of weekly blog posts that will feature what content will be covered in each Pluralsight module, followed by an announcement of the courses release.

So, keep an eye out for that.

Post 5 – Building Your First Lightning Web Component for Salesforce Series

This will be the fifth of a series of posts I will be doing over the next few weeks. They will all lead up to the introduction of my new course in January 2020 titled, “Building Your First Lightning Web Component for Salesforce” from Pluralsight. These posts will contain final code snippets of the code used in each course module, but will not include all the tips and best practices about using Visual Studio Code and SFDX, along with the way I personally approach teaching in my video courses.

Converting Aura Components to Lightning Web Components

In this module, I will be sharing things I learned based on mistakes I made when I first converted an Aura app to LWC’s. This was the result of that attempt.

For a while I intended to use what I did in that first converted app for this course, but luckily for you, I did not. Instead, I contacted my friend Kevin Hill (@KevinJHill) at Salesforce and he volunteered to review my app. He politely suggested that I make a few changes and thank goodness I did.

The biggest mistake I made was not fully accepting this inevitable truth at first:

“The LWC programming model is fundamentally different than the Aura model”

That message is so important to your success with LWC’s, so here it is again:

I did finally accept this and therefore re-designed the solution I ended up using for this course. The version I will show in the course may look similar to the original version, but underneath it is different and if you watch the course you will even get to see performance results that demonstrate that.

The talented developers at Salesforce (which included Kevin Hill and many others), did an incredible job creating Lightning Web Components. If you attempt to just blindly convert an Aura app to an LWC without accepting that the programming model is different, then you will not get the performance advantages that it provides. And imho, that is like spitting in the face of those GREAT developers at Salesforce.

So, please do not do that. And I hope you watch my course when it is released soon. It is almost finished.

Post 4 – Building Your First Lightning Web Component for Salesforce Series

This will be the fourth of a series of posts I will be doing over the next few weeks. They will all lead up to the introduction of my new course in January 2020 titled, “Building Your First Lightning Web Component for Salesforce” from Pluralsight. These posts will contain final code snippets of the code used in each course module, but will not include all the tips and best practices about using Visual Studio Code and SFDX, along with the way I personally approach teaching in my video courses.

Working With Salesforce Data

The most important thing you need to be aware of when working with Salesforce Data is the Lightning Data Service, or LDS. If you have worked with Aura components, then you have probably already heard about it since it was introduced back in late 2017. The LDS is built on top of the UI or User Interface API. This is the API that Salesforce developers use internally to build the Lightning Experience.

The reason why has to do with the following benefits:

  1. Caching, so loading data is as fast as possible
  2. Progressive loading of data, which also improves performance
  3. Optimization of server calls, which guess what, offers performance advantages.

Hopefully, you are seeing the key factor here.

Using the Lightning Data Service Wire Adapter

As I mentioned in the last post, I am building this solution in stages. In the last post, I created a very simple child component named leadListItem to display all the leads returned by a search term. This was ok, but the output was definitely not pretty. The easiest way to fix that is to take advantage of one of the many LWC base components, which as of Dreamforce 2019, are now mostly available as open source.

And one of the best and easiest to use base components, lightning-datatable offers incredible benefits such as formatting for appropriate data types, header and row level actions, resizing of columns sorting and text wrapping. And there are even more.

I will be replacing the template code in leadList.html that called the leadListItem component, with a call to the lightning-datatable. The HTML will now look like this:

<template>
    <lightning-card title="Lead Search" icon-name="standard:search" class="slds--around_medium">
        <div class="slds-box slds-theme_default">
            <lightning-input
                label="Search Term"
                variant="label-hidden"
                placeholder="Search by name, phone, website, or address"
                type="text"
                value={searchTerm}
                onchange={handleSearchTermChange}>
            </lightning-input>
         </div>
        <div class="slds-m-around_small">
            <lightning-datatable
                key-field="id"
                data={leads}
                columns={cols}
                onrowaction={handleRowAction}
                hide-checkbox-column = "true">
            </lightning-datatable>
            <template if:true={error}>
                // Hint. In the actual course, I will implement something better than this
                The following error was encountered: {error}
            </template>
        </div>
    </lightning-card>
</template>

I will need to remove the JSON data in the JavaScript and add a constant to support the column definitions, as well as a new tracked variable for the columns and another for the error that could be returned and only rendered when there is an actual error using the if:true directive in the HTML template.

To help minimize the number of Apex calls, I will use a common technique that was implemented in the lwc-recipes repo. It involves slightly delaying the dispatch of the newsearch Custom Event.

I will also need to add a new imports command that is used to call Apex Code that returns results from a search. And, I will need to add another imports for the wire directive to the top import command. The wire directive is used to read Salesforce data reactively and when the data is provisioned, it automatically re-renders the component. This will be implemented in loadLeads.

And finally, there will be a handler that uses the navigation service to navigate the user to the Lead record page if they decide to click the info icon displayed in the last datatable column. The code for the leadList.js will now look as follows:

import { LightningElement, track, wire } from 'lwc';
import searchLeads from '@salesforce/apex/LeadSearchController.searchLeads';
import { NavigationMixin } from 'lightning/navigation';

/** The delay used when debouncing event handlers before a method call. */
// This code was copied directly from the trailheadapps/lwc-recipes GitHub repo
const DELAY = 350;

// It is a general convention to capitalize constants
const COLS = [
    {
        label: 'Name',
        fieldName: 'Name',
        type: 'text'
    },
    {
        label: 'Title',
        fieldName: 'Title',
        type: 'text'
    },
    {
        label: 'Company',
        fieldName: 'Company',
        type: 'text'
    },
    {
        label: 'View',
        type: 'button-icon',
        initialWidth: 75,
        typeAttributes: {
            title: 'View Details',
            alternativeText: 'View Details',
            iconName: 'action:info'

        }
    }
];

export default class LeadList extends NavigationMixin(LightningElement) {
    @track leads = [];
    @track searchTerm;
    @track cols = COLS;
    @track error;
    
    handleSearchTermChange(event) {
        this.searchTerm = event.target.value;
        if (this.leads) {
            const selectedEvent = new CustomEvent('newsearch', {detail: this.searchTerm});
            window.clearTimeout(this.delayTimeout);
            // eslint-disable-next-line @lwc/lwc/no-async-operation
            this.delayTimeout = setTimeout(() => {
                this.dispatchEvent(selectedEvent);
            }, DELAY);
        }
    }

    @wire(searchLeads, {
        searchTerm: '$searchTerm'
    })
    loadLeads({ error, data }) {
        if (data) {
            this.leads = data;
            this.error = undefined;
        } else if (error) {
            this.error = error;
            this.leads = undefined;
        }
    }

    handleRowAction(event) {
        const row = event.detail.row;
        this.record = row;
        this[NavigationMixin.Navigate]({
            type: 'standard__recordPage',
            attributes: {
                recordId: row.Id,
                actionName: 'view',
            },
        });
    }

}

The last thing to do is to create the Apex class that will do the actual search of the Salesforce data. It will use a SOSL query to perform a special kind of search across multiple fields in a single object. Notice that the searchLeads method includes an @AuraEnabled tag, as well as the cacheable = true. This ensures the data returned will be cached, which is perfect for mutable data such as the lead addresses. The code for that will look as follows:

public with sharing class LeadSearchController {
    
    @AuraEnabled(cacheable=true)
    public static List<Lead> searchLeads( String searchTerm ) {
        List<Lead> leads = new List<Lead>();
        if ( String.isNotBlank( searchTerm ) ) {
            List<List<SObject>> searchResults = [
                FIND :searchTerm
                RETURNING Lead(
                    Id, Name, Title, Company,
                    Street, City,
                    State, PostalCode
                    ORDER BY Name
                    LIMIT 10
                )
            ];
            leads = searchResults[0];
        }
        return leads;
    }
}

Using the CLI to Load Data

At this point, if you were to save and push all this code to your scratch org and then open the Lead Locator tab and do a search, what do you think would happen?

Well, you should get nothing returned because by default scratch orgs are not loaded with any Lead data. But, we can use some very handy CLI commands to export data from another developer org and then import it into our scratch org as JSON data.

I have already used the export command to get 10 lead records from a developer org. That command looked like the following:

sfdx force:data:tree:export --query \                                                                	"SELECT ID, FirstName, LastName, Phone, Company, Title, Street, City, \ 		State, PostalCode FROM Lead limit 10" \                                                	
--outputdir ./data --json

And to import them, I will only need to use the terminal in Visual Studio Code to execute another CLI command that looks like this:

sfdx force:data:tree:import -f data/Lead.json -u <your scratch org username here>

Adding the Lead Map Component

To finish off the solution, I will need to add the leadMap component. It will use another very useful Lightning base component called lightning-map. That base component can display multiple locations using geocoding and mapping imagery from Google Maps. The leadList.html for that component will look like this:

<template>
    <template if:true={leads}>
        <lightning-map
                zoom-level="11"
                map-markers={markers}
                markers-title="Leads">
        </lightning-map>
    </template>
    <template if:true={error}>
            // Hint. In the actual course, I will implement something better than this
            The following error was encountered: {error}
    </template>
</template>

The leadList.js file will import the same LeadSearchController code used in the leadList, but remember that this data is cacheable. And the @wire directive will do a search using a new variable called searchInput. This variable will be passed to the leadMap component as a public variable from the owner component using the @api directive. The final code for leadList.js will look like this:

import { LightningElement, track, wire, api } from 'lwc';
import searchLeads from '@salesforce/apex/LeadSearchController.searchLeads';

export default class leadMap extends LightningElement {
    @track markers = [];
    @track error;
    @track leads;

    // Private variable
    searchTerm;

    @api get searchInput() {
        return this.searchTerm;
    }

    set searchInput(value) {
        this.searchTerm = value;
    }

    @wire(searchLeads, {
       searchTerm: '$searchInput'
    })
    loadLeads({ error, data }) {
        if (data) {
            this.leads = data;
            this.markers = data.map(lead => {
                return {
                    location: {
                        Street: lead.Street,
                        State: lead.State,
                        City: lead.City,
                        PostalCode: lead.PostalCode
                    },
                    title: JSON.stringify(lead.Name),
                    icon: 'utility:pinned'
                }
            })
            this.error = undefined;
        } else if (error) {
            this.error = error;
            this.leads = undefined;
            this.markers = [];
        }
    }
}

The last thing to change is code in the Owner component. In the myFirstLWC.html, I will need to replace the placeholder text with the a call to the new leadList child component. But, to prevent the map from being displayed when the user first loads the page, I will need to use another CustomEvent called searchcomplete. If no search has been done, then the user will get a helpful info message displayed. The HTML code for the owner will now look like this:

<template>
    <div class="c-container">
            <lightning-layout multiple-rows="true">
                <lightning-layout-item padding="around-small" size="12">
                    <lightning-layout>
                        <lightning-layout-item padding="around-small" size="6">
                            <div class="slds-box slds-theme_default">
                                <c-lead-list onnewsearch={handleNewSearch}
                                onsearchcomplete={handleSearchComplete}></c-lead-list>
                            </div>
                        </lightning-layout-item>
                        <lightning-layout-item padding="around-small" size="6">
                            <div class="slds-box slds-theme_default">
                                    <lightning-card title="Lead Map" icon-name="action:map" class="slds--around_medium">
                                        <template if:true={searchComplete}>
                                            <c-lead-map search-input={searchInput}></c-lead-map>
                                        </template> 
                                        <template if:false={searchComplete}>
                                            <div class="slds-notify slds-notify_alert slds-theme_alert-texture slds-theme_info" role="alert">
                                                <span class="slds-assistive-text">info</span>
                                                <h2>You will need to enter a search term before a map is displayed.</h2>
                                            </div>
                                        </template> 
                                    </lightning-card>  
                                </div>
                        </lightning-layout-item>    
                    </lightning-layout>
                </lightning-layout-item>
            </lightning-layout>
        </div>
</template>

Of course, this will mean I will also need to modify the myFirstLWC.js file to include a handler for that new CustomEvent. This code will now look as follows:

import { LightningElement, track } from 'lwc';

export default class MyFirstLWC extends LightningElement {
    @track searchTerm;
    @track searchInput;
    @track searchComplete = false;

    handleNewSearch(event) {
        this.searchTerm = event.target.value; 
    }

    handleSearchComplete(event) {
        this.searchInput = event.detail;
        this.searchComplete = true;
    }
}

And to explain all this in terms of the component communication, consider the following diagram:

But, the course is not done, and the best is yet to come in the next post in which I will go over converting Aura components using an example similar to this with a completely different approach that I think you will find very interesting.

And finally, if you are super excited about this, you might want to consider taking advantage of this limited time offer from Pluralsight for 40% off an annual subscription until December 6, 2019.

40% Off Pluralsight – Last Chance to Save

Post 3 – Building Your First Lightning Web Component for Salesforce Series

This will be the third of a series of posts I will be doing over the next few weeks. They will all lead up to the introduction of my new course titled, “Building Your First Lightning Web Component for Salesforce” from Pluralsight. These posts will contain code snippets of the code used in the course, but will not include all the tips and best practices about using SFDX, along with the way I personally approach teaching in my video courses.

You also have to realize that the solution is built in stages and so the code you see here is not exactly what you will see by the end of the next module. For all that, you will just have to wait and watch the course, which I hope you do.

And Finally, I know there has been a big delay between the first two posts and these remaining posts, but I promise you that the delay will have been worth the wait. I am VERY proud of how this course is turning out and feel like it will be my best yet. 

Component Design

LWC’s are similar to Aura components in the fact that you should consider each component as an application building block. And just like with Aura components, most LWC’s will contain many smaller, nested components. The biggest difference is that the communication patterns between Aura components and LWC’s is VERY different.

LWC Nested Composition

NestedComposition

In this course, we will actually be creating multiple LWC components that demonstrate a nested pattern. At the outermost layer we will have a Lightning App Page and inside of that will be an owner or container component. The owner can contain other components, which also contain other components. What is happening here is that we have a parent-child relationship going on and that is very important is determining how data is passed between LWC components.

Creating the Owner Component

At first this component (which we will name myFirstLWC) will just contain placeholder text for where the two components it will contain will ultimately reside. Here is the HTML we will use for now:

<template>
    <div class="c-container">
            <lightning-layout multiple-rows="true">
                <lightning-layout-item padding="around-small" size="12">
                    <lightning-layout>
                        <lightning-layout-item padding="around-small" size="6">
                            <div class="slds-box slds-theme_default">
                                <h2>TO DO: Add List LWC Component here</h2>
                            </div>
                        </lightning-layout-item>
                        <lightning-layout-item padding="around-small" size="6">
                            <div class="page-section page-main">
                                <h2>TO DO: Add Map LWC Component here</h2>
                            </div>
                        </lightning-layout-item>
                    </lightning-layout>
                </lightning-layout-item>
            </lightning-layout>
        </div>
</template>

You will also need to modify the metadata file so it exposes this component (but ONLY this component since it is the owner) to the Lightning App Builder.

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="MyFirstLWC">
    <apiVersion>47.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>     
      <target>lightning__RecordPage</target>
      <target>lightning__AppPage</target>
      <target>lightning__HomePage</target>
  </targets>
</LightningComponentBundle>

  1. Type “Lightning App” in Quick Find and select Lightning App Builder.
  2. Click New to start the Wizard.
  3. Leave the default on App Page and click Next.
  4. Enter the label “Lead Locator” and click Next.
  5. Select One Region and click Finish.
  6. In the Builder, scroll down to to the Custom List and drag the myFirstLWC onto the design surface.
  7. Click Save.
  8. Click Activate when prompted.
  9. From the Activation Wizard, accept the defaults, and select the Lightning Experience tab.
  10. Select Sales and click Add Page to app.
  11. Click Save.
  12. Click Back to return to Setup.
  13. Click the App Launcher and select the Sales app.You should see the Lead Locator app and you should select it to see your very basic app so far.

Creating the LeadList Component

The Here is the HTML for our leadList component. Notice that it contains two other nested components. One is a Lightning base component called lightning-input and the other is a custom one yet to be created called lead-list-item.

<template>
    <lightning-card title="Lead Search" icon-name="standard:search" class="slds--around_medium">
        <div class="slds-box slds-theme_default">
            <lightning-input
                label="Search Term"
                variant="label-hidden"
                placeholder="Search by name, phone, website, or address"
                type="text"
                value={searchTerm}
                onchange={handleSearchTermChange}>
            </lightning-input>
            <h3>Leads for {searchTerm}</h3>
        </div>
        <div class="slds-m-around_small">
            <template if:true={leads}>
                <template for:each={leads} for:item="lead">
                    <c-lead-list-item key={lead.Id} lead={lead} ></c-lead-list-item> 
                </template>
            </template>
        </div>
    </lightning-card>
</template>

Since this module is only about Composition and not about data, the JavaScript for this component will just contain some static JSON code to represent the lead data. It will also use the Track decorators for the leads array and the searchTerm, which allow you to keep track of a properties value when it is re-rendered.

Most importantly, it will follow best practices and use the simplest way to communicate with events by using a standard CustomEvent called newsearch.

import { LightningElement, track} from 'lwc';

export default class LeadList extends (LightningElement) {
    @track leads =[];
    @track searchTerm;

    handleSearchTermChange(event) {
        this.searchTerm = event.target.value;
        const selectedEvent = new CustomEvent('newsearch', {detail: this.searchTerm});
        this.dispatchEvent(selectedEvent);
    }

    leads = [
        {
            "Id": "LeadRef1",
            "Name": "Bertha Boxer",
            "Title": "Director of Vendor Relations",
            "Company": "Farmers Coop. of Florida",
            "Street": "321 Westcott Building",
            "City": "Tallahassee",
            "State": "FL",
            "PostalCode": "32306"
        },
        {
            "Id": "LeadRef2",
            "Name": "Phyllis Cotton",
            "Title": "CFO",
            "Company": "Chamber of Commerce",
            "Street": "300 E Park Ave",
            "City": "Tallahassee",
            "State": "FL",
            "PostalCode": "32301"
        },
        {
            "Id": "LeadRef3",
            "Name": "Jeff Glimpse",
            "Title": "SVP, Procurement",
            "Company": "Tallahassee Taxes",
            "Street": "1327 Colorado St",
            "City": "Tallahassee",
            "State": "FL",
            "PostalCode": "32304"
        }
    ];

}

 Modifying the Owner Component

Since we added a CustomEvent to the leadList component, we will need to add some JavaScript to the owner component, myFirstLWC that will handle this event.

import { LightningElement, track } from 'lwc';

export default class MyFirstLWC extends LightningElement {
    @track searchTerm;

    handleNewSearch(event) {
        this.searchTerm = event.target.value; 
    }
}

We will also need to modify the HTML so that we remove the placeholder text for the leadList component. Notice though how it is named. All LWC’s will be rendered with the c namespace, followed by a hyphen and then the component name, which is also separated by a hyphen. LWC knows that the leadList component is two words because we used kebab or camel case when naming it. This is a commonly used HTML standard and it means that the component must start with a lowercase letter and the other letter must be capitalized with no spaces in between, which is how we named the leadList component.

<c-lead-list onnewsearch={handleNewSearch}></c-lead-list>

Creating the leadListItem Component

This is just a very basic component that will display the results of the search. Not much to it for now.

<template>
    <lightning-layout vertical-align="center">
        <lightning-layout-item padding="around-small">
            <p>{lead.Name}</p>
        </lightning-layout-item>
        <lightning-layout-item padding="around-small">
            <p>{lead.Title}</p>
        </lightning-layout-item>
        <lightning-layout-item padding="around-small">
            <p>{lead.Company}</p>
        </lightning-layout-item>
    </lightning-layout>
</template>

And here is the JavaScript for that component. It will use the api decorator since the lead that is passed to it is a public property.

import { LightningElement, api } from 'lwc';

export default class LeadListItem extends LightningElement {
    @api lead;
}

So that is all we have for now. If you push all the code we have here and go to do a search, you should see the term you type displayed right below it, but not much else is happening yet. But stay tuned for the next post, because that is where all the magic will happen and the solution will come together.

Post 2 – Building Your First Lightning Web Component for Salesforce Series

This will be the second of a series of posts I will be doing over the next few weeks. They will all lead up to the introduction of my new course titled, “Building Your First Lightning Web Component for Salesforce” from Pluralsight.

Setting Up Your Development Environment (in 5 somewhat easy steps)

Step 1: Signup for a Developer Org

I know you may already have one of these, but  I suggest you sign up for another one since this will be used primarily as a DevHub. You go can signup here.

The primary function of the DevHub is to create and manage scratch orgs. To enable the DevHub, go to Setup and type Dev in the Quick Find Box and go to the DevHub Page. Click the Enable button and just remember that once enabled, you cannot disable a DevHub org.

Step 2: Install the latest version of Visual Studio CodeVSCode

Even if you already have Visual Studio Code running on your machine, I suggest you to download and install this version by going here.

This is this is the IDE that Salesforce has chosen to recommend and fully support for LWC.

Step 3: Install the Salesforce CLI

The CLI, or Command Line Interface helps to simplify Salesforce development by allowing you as a developer to pretty much do everything you need to do to develop, test and deploy your code.

Be aware that unlike the rest of Salesforce,  the CLI is updated weekly.  You can download the version for your operating system here. Just remember to run the sfdx update command frequently so you know you have the latest version.

Step 4: Install the Salesforce Extension Pack for Visual Studio Code

To get this installed, you should launch Visual Studio Code and when you do,you will want to start by clicking the extensions icon on the left toolbar. If you start to type in Salesforce, you should see a list of all the Salesforce extensions. For now, you will want to click install for the Salesforce Extension Pack.

SalesforceCLI

Step 5: Install the Java Platform Standard Edition Development Kit

This can be found on the Oracle website and you will want to make sure you have installed the latest version 8 or 11 for your particular operating system. During the installation, you will need to ensure that the install points to the directories listed here for either Windows or the mac:

  • Windows: C:\Program Files\Java\jdk1.8.0_221.jdk\
  • MacOS: /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home.

Once the installation is complete you will also need to change a setting in VS Code to reflect this. You do this by going to File, Preferences and Settings. This is where you will point VS code to the right Java install. Enter apex java and select Salesforcedx-vscode-apex. Notice that the path here is not the one you installed to.

UPDATED Instructions below:

So,we will need to change this. You can do that by clicking on the input box, right below the wrong setting and then entering the correct one for your operating system. I am on Windows here. And finally you will relaunch VS Code.

After you re-launch, go to the terminal and type java -version and you should see the output like below.

SettingsJava

I know this seems like a pain, but there are some features in the Salesforce Extension pack that rely on this SDK, so it is important that you install it.

That’s it (Phew)…

See you next week, when we will be talking about composition and communication of your LWC’s.

Relax, here are some important things to know about Lightning Web Components (LWC)

On December 13, 2018, Salesforce announced the upcoming release of Lightning Web Components at Salesforce World Tour in New York. In a nutshell, Lightning Web Components is a new programming model that represents a big shift in Salesforce development towards web components and modern JavaScript development.

If you are an existing Salesforce developer, then that last statement may have made you cringe a bit and you may now be thinking:

“Big Shift? Wait…What?”

“Didn’t we just go through a big shift with Lightning Components?”

“Are you saying I have to learn something new again? I am still not even sure how Lightning Components work. Please tell me you are kidding!”

To help ease your discomfort, or even if you are excited about the announcement, I will attempt to answer some questions you may have:

Aura Components aren’t going away and will work very well with LWC’s

And now you might be asking, “Wait, what are Aura Components?”

“Aura Components” are what was previously known as “Lightning Components”. They will now be known as Aura Components because there was a need to distinguish them from the new Lightning Web Components. The name “Aura” is used because these components are based on the Aura framework. Lightning Web Components are named as such because they are based on standard web components.

Basically, there are now two ways to develop Lightning components:

  1. Aura components – what you have known as lightning components
  2. Lightning Web Components – the new way to create lightning components

So if you have invested a lot of time learning about Lightning Components, don’t worry. Those components are not going anywhere and you can continue to create and use them. At the same time, you can start to learn about the new Lightning Web Components and once you are ready you can start building either kind, or both. The really cool thing is that LWC’s are designed to work together with aura components.

Components you build with LWC should render faster

LWC’s will take advantage of native web standards that exist in the browser. This means there is no added abstraction layer, like the Aura framework (or any framework for that matter) to slow things down. It also means LWC’s will most likely render faster than aura components.

That does not mean that aura components are bad and should be avoided. However, in cases where performance is really important to a components success, you should probably consider LWC’s.

Developing LWC’s is fun!

I have been fortunate to be part of the pilot for LWC’s and the overwhelming feedback that has been coming in from all the other people that are part of the pilot is that “Developing LWC’s is fun”. One reason it is fun, is because developers are able to finally use modern JavaScript syntax that has been off limits to aura components. And if you are not sure what I am talking about with modern JavaScript, check out this post.

As an added bonus, because LWC’s utilize common web standards, it should be easier to find developers with the skills to develop LWC’s. It might also be easier to transition existing developers to using LWC’s because there is no additional framework to learn.

You need to check out the new and updated apps in the Sample Gallery

You may not know this, but the Developer Relations team hosts a very cool sample app gallery available here. This app gallery features LWC updated versions of all the sample apps you have grown to love (like Dreamhouse and Northern Trail Outfitters), but it also includes two new sample apps you will love even more:

  1. Recipes – This app is all about bite-sized (30 lines of code or less) LWC recipes. Once installed you will have access to several tabs and each one features multiple LWC’s that highlight a very specific use case. The best part about this app is that you can rest assured that best practices were considered right from the start. Feel free to use this as the starting point for all your new LWC’s.

Recipes.png

  1. E-Bikes – This represents what an actual retailer might build using LWC’s. It shows off all the best of LWC’s in a real-world kind of application.

ebikes.png

 

You cannot create LWC’s in Dev Console and need to use VS Code and the extensions

Sorry to say, but you cannot create LWC’s in Developer Console. For now (and Safe harbor, note the word “now”), you will need to use Visual Studio Code and the CLI extensions for SalesforceDX. Now, just in case you have not dipped your toes into the world of SalesforceDX, this represents your perfect opportunity to get started. I would suggest you start by checking out this great trail on Trailhead.

Going GA in Spring 19 – At that time it will support LEX, Mobile App and Communities

LWC’s will not be generally available until the release of Spring 19, which should be in February 2019. But, there is no reason to wait until then. You can sign up for a pre-release org now and your first step after that should be to go to Trailhead and earn the Quick Start: Lightning Web Components badge. It only takes 20 minutes and it will get you setup with everything you need to start building your own LWC’s.

Hopefully, you are feeling a little less apprehensive about this shift. It truly is a GREAT time to be a developer and I have no doubt that in time you will come to love creating LWC’s. Have fun!!!

Check out the Salesforce API Explorer

In an attempt to make things easier for us developers, the Developer Relations group has created a nice little tool called the Salesforce API Explorer.

Screen Shot 2018-08-23 at 1.48.18 PM

What It Includes Now

The first thing you should know about this tool is that it is still in Developer Preview and the team that created it is actively seeking feedback on how it can be improved. You can submit feedback right from the Send us Feedback link at the top.

As of this writing, there are only the following two API’s featured here:

  • Force.com REST API
  • Marketing Cloud REST API

How You Can Help

Remember when I said this was still in Preview mode? Well, you can easily vote on which API’s will be included next by clicking the like button underneath the API’s listed in the “Which API’s would you like to see here next?” section. Please take the time to go through the list and vote for which ones you would like to see appear next. Come on. You can’t complain about a lack of good documentation without taking the time to be part of a solution.

Why It is So Cool

This Explorer tool is not only cool because of the fact that it will list all the API’s in one place in a nice readable way. But, it is VERY cool when you consider the nice “Try it now” feature that lets you see the results of executing any of the API calls against your developer org.  You just need to provide credentials for your org.

You will then select a Resource, such as Account and then an endpoint, such as FindAccountById. Not only does this show you all the documentation you need for that endpoint, but you can try it out by doing the following:

  1. Click Try it Now
  2. Enter any path parameters (if needed), such as the Account ID
  3. Click Execute
  4. A Live response appears on the right

Screen Shot 2018-08-23 at 6.35.09 PM.png

Boom! You don’t have to go into workbench. You can do everything you need right here in the explorer tool. Cool, right?

Why the recordForm component is so AWESOME!!!

The Summer 18 Salesforce release is almost here, and as usual it contains lots of great features. But one new feature, the lightning:recordForm component has not gotten the coverage I think it deserves. So, I wanted you all to know just how cool this new Base Lightning Component really is, by showing you the code for a Quick Contact component

To truly appreciate how far we have come with Lightning development, I would have to show you what the equivalent code without Base Components looked like. But, that would be like bringing you back to the stone ages and who needs that. Instead I will just point you to the code used to build something similar using what was available before the new recordForm component.

And to see that, I will direct you to a great tutorial on GitHub that was designed to show you how to Build Lightning Components with Salesforce DX. And if you have not started using Salesforce DX yet (and I cannot imagine why you have not) then this is the perfect opportunity to get started. In this step-by-step tutorial, you will be led through creating 3 lightning components:

Component # 1 – quickContactView

Uses the lightning:recordViewForm and several lightning:outputField base components to create a read-only version of the Quick Contact Form.
Screen Shot 2018-07-05 at 10.28.48 AM

Component # 2 – quickContactEdit

Uses the lightning:recordEditForm and several lightning:inputField base components to create a editable version of the Quick Contact Form.
Screen Shot 2018-07-05 at 10.30.13 AM

Component # 3 – quickContactViewEdit

Uses aura:if‘s and a lightning:buttonStateful base components to toggle between the quickContactView and quickContactEdit components.
Screen Shot 2018-07-05 at 10.31.32 AM
The result of using these 3 components, is a form that looks like the following:

Screen Shot 2018-05-28 at 10.14.26 AM

In this version of the component, the user must first click the “Click to Edit” button before they are able to edit the contact fields. This all works fine, but wouldn’t it be better if you could achieve this same functionality by creating only one component?

Ok, you don’t really have to answer that…because the answer is obviously, “YES!”.

The Single Component Alternative

Good news. As of the Summer 18 release, you will be able to do exactly that by using the newly available lightning:recordForm base lightning component. Using it is dead simple and involves code such as the following:
Screen Shot 2018-07-05 at 10.40.50 AM

In that code snippet, I only had to use one attribute and one recordForm base lightning component in a single component to reproduce all the functionality that previously required 3 separate components. BAM! That is practically magic.

So hopefully now you get why this new base lightning component is perhaps the coolest one ever.

Hope you get a chance to check it out and please let me know what you think.

If you found this article useful, you might want to checkout my latest course on Pluralsight titled, Lightning Component Development Best Practices, where I talk about base lightning components and a lot more.