Lightning Web Component First Example

Let’s discuss here the complete end to end application using the Lightning web components. This example, we will be seeing the application that will be used to maintain the issue log. The app which we will be building looks like below.  Please refer to this link for environment setup.

 

1. Create an apex class 

 

Create an Apex class that will fetch the list of issues from the database. This class fetches the list of issues from the database.

public with sharing class IssueController {
    @AuraEnabled(cacheable=true)
    public static List<Issue__c> getAllIssues() {
       return [SELECT Id, Name, Assigned_To__c, Description__c,Priority__c,Resolved__c FROM Issue__c Order by Name];
    }
}

2.Create an Issue Log LWC

Create a lightning component using the below SFDX command

This component will do

  • Insert the new record into the issue log using wire services
  • Fire an event with the newly created record.
  • Show toast message on insert the new record.
sfdx force:lightning:component:create --type lwc --componentname issuelog --outputdir force-app\main\default\lwc 

Use this code in issuelog.html

<template>
    <lightning-card title="Log Issue" icon-name="standard:record">
        <div class="slds-m-around_medium">
            <lightning-input label="Issue Description" type="text" onchange={handleChange} class="slds-m-bottom_x-small"></lightning-input>

            <lightning-combobox name="Priority" label="Priority" value="" placeholder="Select Priority"
             options={options}
                onchange={handleChange}></lightning-combobox>

            <lightning-button label="Log Issue" variant="brand" onclick={createIssue}></lightning-button>
        </div>
    </lightning-card>
</template>

Use this code in issuelog.js

import {
    LightningElement,
    track,
    wire
} from 'lwc';
import {
    ShowToastEvent
} from 'lightning/platformShowToastEvent';
import {
    createRecord
} from 'lightning/uiRecordApi';
import ISSUE_OBJECT from '@salesforce/schema/Issue__c';
import ASSIGNED_FIELD from '@salesforce/schema/Issue__c.Assigned_To__c';
import DESCRIPTION_FIELD from '@salesforce/schema/Issue__c.Description__c';
import PRIOITY_FIELD from '@salesforce/schema/Issue__c.Priority__c';

export default class Issuelog extends LightningElement {
    @track description;
    @track proirity;
    get options() {
        return [{
                label: 'Low',
                value: 'Low'
            },
            {
                label: 'Medium',
                value: 'Medium'
            },
            {
                label: 'High',
                value: 'High'
            },
            {
                label: 'Critical',
                value: 'Critical'
            },
        ];
    }
    handleChange(event) {
        if (event.target.label === 'Issue Description') {
            this.description = event.target.value;
        }
        if (event.target.label === 'Priority') {
            this.proirity = event.target.value;
        }
    }
    createIssue() {
        const fields = {};
        fields[DESCRIPTION_FIELD.fieldApiName] = this.description;
        fields[PRIOITY_FIELD.fieldApiName] = this.proirity;

        const recordInput = {
            apiName: ISSUE_OBJECT.objectApiName,
            fields
        };
        createRecord(recordInput)
            .then(issue => {
                console.log('issue' + JSON.stringify(issue));
                const event = new CustomEvent('newrecord', {
                    detail: {
                        data: issue
                    },
                });
                this.dispatchEvent(event);
                console.log('event fired');
                this.dispatchEvent(
                    new ShowToastEvent({
                        title: 'Success',
                        message: 'Issue Logged with Record ',
                        variant: 'success',
                    }),
                );
                this.description = '';
            })
            .catch(error => {
                console.log('error' + JSON.stringify(error, null, 2));

                this.dispatchEvent(
                    new ShowToastEvent({
                        title: 'Error creating record',
                        message: error.message,
                        variant: 'error',
                    }),
                );
            });
    }
}

 

Understand the issuelog.js

 

The below get method will be returning the lits of the options for combo box .insted of passing the hardcoded values to get method you can able to use the getPicklist Values wired Adapter

get options() {
        return [{
                label: 'Low',
                value: 'Low'
            },
            {
                label: 'Medium',
                value: 'Medium'
            },
            {
                label: 'High',
                value: 'High'
            },
            {
                label: 'Critical',
                value: 'Critical'
            },
        ];
    }

The below code will handle the change event from the description and priority fields changes.

 handleChange(event) {
        if (event.target.label === 'Issue Description') {
            this.description = event.target.value;
        }
        if (event.target.label === 'Priority') {
            this.proirity = event.target.value;
        }
    }

The following code in the create issue method will be used to save the record and will be passed to createRecord wire adapter

const fields = {};
        fields[DESCRIPTION_FIELD.fieldApiName] = this.description;
        fields[PRIOITY_FIELD.fieldApiName] = this.proirity;

        const recordInput = {
            apiName: ISSUE_OBJECT.objectApiName,
            fields
        };

createRecord will be used to save the record and in the same method, we will firing an event with a newly created record using the new CustomEvent.

 createRecord(recordInput)
            .then(issue => {
                console.log('issue' + JSON.stringify(issue));
                const event = new CustomEvent('newrecord', {
                    detail: {
                        data: issue
                    },
                });
                this.dispatchEvent(event);

the following code will be used to dispatch the toast message to UI when the record is saved of failed

 

 this.dispatchEvent(
                    new ShowToastEvent({
                        title: 'Success',
                        message: 'Issue Logged with Record ',
                        variant: 'success',
                    }),
                );

 

 

Use this issuelog.js-meta.xml file to configure the issue log.

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

</LightningComponentBundle>

 

3.Create an Issue List LWC

create a lightning component using the following sfdx command.

This component will be

  1. Container component for the issue log component
  2. Received an event that is the trigger by issue log component
  3. handler the resolved checkbox checked and unchecked and navigation logic.

 

sfdx force:lightning:component:create --type lwc --componentname issuelist --outputdir force-app\main\default\lwc 

 

Use this issuelist.html code

<template>
    <lightning-card title="Add New Issue ">
        <c-issuelog onnewrecord={handleNewRecord}></c-issuelog>
    </lightning-card>
    <lightning-card title="List of Issues">
        <div class="slds-m-horizontal_large">
            <template if:true={issues}>
                <template if:true={issues}>
                    <table class="slds-table slds-table_cell-buffer slds-no-row-hover slds-table_bordered">
                        <thead>
                            <tr class="slds-line-height_reset">
                                <th class="" scope="col">
                                    <div class="slds-truncate" title="Name">Name</div>
                                </th>
                                <th class="" scope="col">
                                    <div class="slds-truncate" title="Description">Description</div>
                                </th>
                                <th class="" scope="col">
                                    <div class="slds-truncate" title="Priority">Priority</div>
                                </th>
                                <th class="" scope="col">
                                    <div class="slds-truncate" title="Resolved">Resolved</div>
                                </th>
                            </tr>
                        </thead>
                        <tbody>
                            <template for:each={issues} for:item="issue">

                                <tr key={issue.Id}>
                                    <td data-label="Name">
                                        <a value={issue.Id} data-recordid={issue.Id} onclick={handleNameClicked}>
                                            {issue.Name}</a>
                                    </td>
                                    <td data-label="Description"> {issue.Description__c}</td>
                                    <td data-label="Priority"> {issue.Priority__c}</td>
                                    <td data-label="Resolved">
                                        <lightning-input data-recordid={issue.Id} type="checkbox" checked={issue.Resolved__c}
                                            value={issue.Resolved__c} onchange={handleChecked}></lightning-input>

                                    </td>
                                </tr>
                            </template>
                        </tbody>
                    </table>
                </template>
                <template if:false={issues.length}>
                    No Data Found
                </template>
            </template>
            <template if:true={error}>
                Error While Loading data from Salesforce
            </template>
        </div>
    </lightning-card>
</template>

use this code in issuelist.js

import {
    LightningElement,
    wire,
    api,
    track
} from 'lwc';
import {
    ShowToastEvent
} from 'lightning/platformShowToastEvent';

import {
    createRecord,
    generateRecordInputForUpdate,
    updateRecord,
    deleteRecord,
} from 'lightning/uiRecordApi';

import {
    refreshApex,
    getSObjectValue
} from '@salesforce/apex';

import getAllIssues from '@salesforce/apex/IssueController.getAllIssues';

import {
    NavigationMixin
} from 'lightning/navigation';


export default class Issuelist extends NavigationMixin(LightningElement) {
    @track issues;
    @track error;
    wiredIssueResult;
    @track recordId;
    @api currentRecord
    @wire(getAllIssues)
    wiredIssue(result) {
        this.wiredIssueResult = result;
        if (result.data) {
            this.issues = result.data;
            this.error = undefined;
        } else if (result.error) {
            this.error = result.error;
            this.issues = undefined;
        }
    }


    handleNewRecord(evt) {
        return refreshApex(this.wiredIssueResult);
    }
    handleChecked(event) {
        event.preventDefault();
        const recId = event.target.dataset.recordid;
        let record = {
            fields: {
                Id: recId,
                Resolved__c: event.target.checked,
            },
        };
        updateRecord(record)
            .then(() => {
                this.dispatchEvent(
                    new ShowToastEvent({
                        title: 'Success',
                        message: 'Record is updated',
                        variant: 'success',
                    }),
                );
            })
            .catch(error => {
                this.dispatchEvent(
                    new ShowToastEvent({
                        title: 'Error while updating record',
                        message: error.message,
                        variant: 'error',
                    }),
                );
            });

    }
    handleNameClicked(event) {
        event.preventDefault();
        const recId = event.target.dataset.recordid;
        this[NavigationMixin.Navigate]({
            type: 'standard__recordPage',
            attributes: {
                recordId: recId,
                objectApiName: 'Issue__c',
                actionName: 'view'
            },
        });

    }

}

 

understand the code

The following code is used to handle the event that is received from the issue log .here I am simply refreshing the wire adapter which will get the updated values

 handleNewRecord(evt) {
        return refreshApex(this.wiredIssueResult);
    }

You can able to handle the event values as shown below as well and get the event values and parse it.

this.issues = [
    ...this.issues,
    {
        "Id": evt.detail.data.id,
            "Name": evt.detail.data.fields.Name.value,
            "Assigned_To__c": evt.detail.data.fields.Assigned_To__c.value,
            "Description__c": evt.detail.data.fields.Description__c.value,
            "Priority__c": evt.detail.data.fields.Priority__c.value,
            "Resolved__c": evt.detail.data.fields.Resolved__c.value
    },
];

 

The following code will be used to update the values when user click on the checkbox resolved

    handleChecked(event) {
        event.preventDefault();
        const recId = event.target.dataset.recordid;
        let record = {
            fields: {
                Id: recId,
                Resolved__c: event.target.checked,
            },
        };
        updateRecord(record)
            .then(() => {
                this.dispatchEvent(
                    new ShowToastEvent({
                        title: 'Success',
                        message: 'Record is updated',
                        variant: 'success',
                    }),
                );
            })
            .catch(error => {
                this.dispatchEvent(
                    new ShowToastEvent({
                        title: 'Error while updating record',
                        message: error.message,
                        variant: 'error',
                    }),
                );
            });

    }

 

The following code is used to fire the navigation event

 handleNameClicked(event) {
        event.preventDefault();
        const recId = event.target.dataset.recordid;
        this[NavigationMixin.Navigate]({
            type: 'standard__recordPage',
            attributes: {
                recordId: recId,
                objectApiName: 'Issue__c',
                actionName: 'view'
            },
        });

    }

 

 

 

Use the below issuelist.js-meta.xml code

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

</LightningComponentBundle>

 

4. Push changes

Push the changes to scratch org using the below SFDX command and add this component to the layout

 

 sfdx force:source:push --forceoverwrite

 

Here is the final output of the code.