Lightning Web Components Making Width Aware

Let us discuss here how to define the lightning web component width aware of the screen. When building web apps, it is sometimes advantageous for components to have awareness of their size and position on the screen. This is useful both for rendering content initially, but also for components that need to know when their size changes. When you add a component to a region on a page in the Lightning App Builder, use @api flexipageRegionWidth to pass the region’s width to the component. Then with some strategic CSS, you can tell the component to render in different ways in different regions at runtime. This example will display the opportunity table and adding different boards based on width as shown below.

In the component’s JavaScript class, use the @api decorator to create a public flexipageRegionWidth property. This property receives the width value of the region that the component resides in on the page. the flexipageRegionWidth will return SMALL ,MEDIUM ,LARGE values

 

Step 1: Create an Apex Class

Create a simple apex class that queries the opportunity and return the data. run the following command from the SFDX

sfdx force:apex:class:create -n GetOppList -d force-app/main/default/apex

Here is the complete code for apex class

public with sharing class GetOppList {
    @AuraEnabled(cacheable=true)
    public static List<Opportunity> getOpp() {
        return [SELECT Id, Name  ,StageName ,CloseDate, Type FROM Opportunity LIMIT 10];
    }
}

 

Step 2: Create a lightning web component

Create a Lightning web component by using the following SFDX command

sfdx force:lightning:component:create --type lwc -n RegionEx -d force-app/main/default/lwc

Here is the RegionEx.html markup code which will display the opportunity table.

<template>
    <div class="slds-text-align_center">
Page Region 1- {flexipageRegionWidth}   
    </div>
    <div class={flexipageRegionWidth}>
        <table class="slds-table">
            <thead>
                <tr class="slds-line-height_reset">
                    <th class="slds-text-title_caps" scope="col">
                        <div class="slds-truncate">Opportunity Name</div>
                    </th>
                    <th class="slds-text-title_caps" scope="col">
                        <div class="slds-truncate">Stage</div>
                    </th>
                    <th class="slds-text-title_caps" scope="col">
                        <div class="slds-truncate">Close Date</div>
                    </th>
                </tr>
            </thead>
            <tbody>
                <template if:true={opps.data}>
                    <template for:each={opps.data} for:item="opp">
                        <tr class="slds-hint-parent"  key={opp.Id}>
                            <td>
                                <div class="slds-truncate" key={opp.Id}>{opp.Name}</div>
                            </td>
                            <td>
                                <div class="slds-truncate" key={opp.Id}>{opp.StageName}</div>
                            </td>
                            <td>
                                <div class="slds-truncate" key={opp.Id}>{opp.CloseDate}</div>
                            </td>
                        </tr>
                    </template>
                </template>


            </tbody>
        </table>

    </div>
</template>

Here is the RegionEx.js JavaScript controller.I n the component’s JavaScript class, use the @api decorator to create a public flexipageRegionWidth property. This property receives the width value of the region that the component resides in on the page.

 

import { LightningElement,api ,wire} from 'lwc';
import getOpp from '@salesforce/apex/GetOppList.getOpp';

export default class RegionEx extends LightningElement {
   @api flexipageRegionWidth;
   @wire(getOpp) opps;
}

Here are the RegionEx.css styles that we will used  based on the region

 .MEDIUM {
    background: red !important;
    background-color: lightblue !important;
    border: 10px solid yellowgreen !important;
}
 .SMALL {
    background: blue !important;
    background-color: royalblue !important;
    border: 10px solid blueviolet !important;
}

Here is the RegionEx.js-meta.xml

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

</LightningComponentBundle>

 

Step 3: Push Changes to Scratch Org 

Now push the changes using this SFDX command

sfdx force:source:push

Add the Lightning web component to the record page and you can able to see the styles based on the region width of the page as shown below.

 

 

 

Advertisement

Platform Events Subscribe using Lightning Component

Platform events are part of Salesforce’s enterprise messaging platform. The platform provides an event-driven messaging architecture to enable apps to communicate inside and outside of Salesforce. Here let us discuss how to subscribe to the platform events in the lightning component using lightning: empApi. The lightning:empApi component provides access to methods for subscribing to a streaming channel and listening to event messages. All streaming channels are supported, including channels for platform events, PushTopic events, generic events, and Change Data Capture events. The lightning:empApi component uses a shared CometD connection.we will be subscribing the platform event object as shown below.
Here is the simple lightning component that will subscribe to the platform events and listen for notifications.
<aura:component implements="flexipage:availableForAllPageTypes ,force:appHostable" access="global" >
    <lightning:empApi aura:id="empApi" />
    <aura:handler name="init" value="{!this}" action="{!c.onInit}"/>
    <aura:attribute name="subscription" type="Object" />
    <aura:attribute name="results" type="Object" />
    
    <lightning:input aura:id="channel" label="channel" name="channel" type="text" value="/event/Order_Fulfillment__e"/>
    <lightning:button label="Subscribe" onclick="{! c.subscribe }" />
    <lightning:button label="Unsubscribe" onclick="{! c.unsubscribe }" disabled="{!empty(v.subscription)}"/>
    
    {!v.results}
    
</aura:component>
({
    // Sets an empApi error handler on component initialization
    onInit : function(component, event, helper) {
        // Get the empApi component
        const empApi = component.find('empApi');
        //  below line to enable debug logging (optional)
           empApi.setDebugFlag(true);
    },
    // Invokes the subscribe method on the empApi component
    subscribe : function(component, event, helper) {
        // Get the empApi component
        const empApi = component.find('empApi');
        // Get the channel from the input box
        const channel = component.find('channel').get('v.value');
        // Replay option to get new events
        const replayId = -1;

        // Subscribe to an event
        empApi.subscribe(channel, replayId, $A.getCallback(eventReceived => {
            // Process event (this is called each time we receive an event)
			component.set('v.results', JSON.stringify(eventReceived.data.payload));
            console.log('Received event 1 ', eventReceived.data);

            console.log('Received event2  ', eventReceived.data.payload);
        }))
        .then(subscription => {
            // Confirm that we have subscribed to the event channel.
            // We haven't received an event yet.
            console.log('Subscribed to channel ', subscription.channel);
            // Save subscription to unsubscribe later
            component.set('v.subscription', subscription);
        });
    },

    // Invokes the unsubscribe method on the empApi component
    unsubscribe : function(component, event, helper) {
        // Get the empApi component
        const empApi = component.find('empApi');
        // Get the subscription that we saved when subscribing
        const subscription = component.get('v.subscription');

        // Unsubscribe from event
        empApi.unsubscribe(subscription, $A.getCallback(unsubscribed => {
          // Confirm that we have unsubscribed from the event channel
          console.log('Unsubscribed from channel '+ unsubscribed.subscription);
          component.set('v.subscription', null);
        }));
    }
})

 

once a platform event is published, you can able to the response from the subscribed lightning component as shown below

Publishing Platform Events

The Salesforce enterprise messaging platform offers the benefits of event-driven software architectures. Platform events are the event messages (or notifications) that your apps send and receive to take further action. Platform events simplify the process of communicating changes and responding to them without writing complex logic. Publishers and subscribers communicate with each other through events. One or more subscribers can listen to the same event and carry out actions. Here we will see how many ways you can able to publish the platform events in Salesforce. After a platform event has been defined in your Salesforce org, publish event messages from a Salesforce app using processes, flows, or Apex or an external app using Salesforce APIs.Here is the simple platform event object we will be using in the examples here

Here are the different ways you can able to publish the platform events in Salesforce

Option 1: Using Process Builder  

You can able to publish the platform events using process builder. To publish event messages, add a Create a Record action to the appropriate process. Where you’d usually pick an object to create, select the platform event. Here is the simple process builder that will publish the platform event when an order is created

This process builder will publish the platform event whenever the order record is created.

Option 2: Using flow 

Another great usage of the flow is you can able to publish the platform events using the flows. Use flows to publish event messages from a Salesforce app as part of some user interaction, an automated process, Apex, or workflow action. To publish event messages, add a Record Create or a Fast Create element to the appropriate flow. Where you’d usually pick an object to create, select the platform event. Here is the simple flow that we will be using it create a platform event on click on the button from the order record. Here is the Fast lookup screen that will fetch the order from the database.

Here is the record create screen that will be inserting the data into the platform event.

Final Flow looks like below

Now create a quick action from the flow and add it to the order page layout. once you click on the quick action then it will publish into the platform events.

Option 3: Using Apex

You can able to publish the platform event using apex. To publish event messages, call the EventBus.publish method. Here is the sample apex trigger that will create platform events.

trigger Ordertrigger on Order (after insert) {
    List<Order_Fulfillment__e> listOfOF = new List<Order_Fulfillment__e>();
    
    for(Order o :Trigger.new){
        Order_Fulfillment__e ofD = new Order_Fulfillment__e() ;  
        ofD.Is_Primary__c = true ; 
        ofD.Order_Date__c = System.today() ;
        ofD.Order_Details__c = o.Description ; 
        ofD.Order_Id__c =o.Id ; 
        ofD.Sales_Price__c = o.TotalAmount ; 
        ofD.Status__c = o.Status ; 
        ofD.Type__c = o.Type;
        listOfOF.add(ofD);
    }
    List<Database.SaveResult> results = EventBus.publish(listOfOF);
    for (Database.SaveResult sr : results) {
        if (sr.isSuccess()) {
            System.debug('Successfully published event.');
        } else {
            for(Database.Error err : sr.getErrors()) {
                System.debug('Error returned: ' +
                             err.getStatusCode() +
                             ' - ' +
                             err.getMessage());
            }
        }
        
    }
}

Option 4: Using External Apps 

You can able to publish the platform events by using third-party apps with API support. For example, you can able to publish the platform events using SoapUI. Please refer to this link 

Option 5: Using Salesforce APIs

External apps use an API to publish platform event messages. Publish events by creating records of your event in the same way that you insert sObjects. You can use any Salesforce API to create platform events, such as SOAP API, REST API, or Bulk API. When publishing an event message, the result that the API returns contains information about whether the operation was successful and the errors encountered. If the success field is true, the event was published for a standard-volume event. For a high-volume event, the publish request is queued in Salesforce and the event message might not be published immediately. If the success field
is false, the event publish operation resulted in errors, which are returned in the errors field. The returned result also contains the Id system field. The Id field value is not included in the event message delivered to subscribers. It is not used to identify an event message, and is not always unique. Subscribers can use the ReplayId system field, which is included in the delivered message, to identify the position of the event in the stream. To publish a platform event message using REST API, send a POST request to the following endpoint.

/services/data/v44.0/sobjects/Order_Fulfillment__e/

You can able to send the post request as shown below from workbench as shown below.

 

 

Render Lists In Lightning Web Components

One of the most common use cases is to iterate through the collection when you are working on data collection. Let’s discuss here what all the different ways to do it in lightning web components. To render a list of items, use for each directive or the iterator directive to iterate over an array. Add the directive to a nested <template> tag that encloses the HTML elements you want to repeat. Please refer this link for web component environment setup

Using for:each directive

Let us discuss here how to use the for:each. When using the for:each directive, use for:item=”currentItem” to access the current item. To assign a key to the first element in the nested template, use the key={uniqueId} directive. Regardless of which directive you use, you must use a key directive to assign a unique ID to each item. When a list changes, the framework uses the key to rerender only the item that changed. The key must be a string or a number, it can’t be an object. You can’t use the index as a value for the key. Assign unique keys to an incoming data set. Here is the simple apex class that will get the data from the account object and its contacts. create an apex class using the below  SFDX command.

sfdx force:apex:class:create -n AccountContactController 

Here is the complete code.

public with sharing class AccountContactController {
     
    @AuraEnabled(cacheable=true)
    public static List<Account> getAccountContactList() {
        return [SELECT Id, Name,(Select Id,Name from Contacts) FROM Account];
    }

}

Below is the lightning web component that will iterate over an array called accounts, which is defined in the component’s JavaScript class.  Run the following SFDX command to create a web component

sfdx force:lightning:component:create --type lwc -n CollectionExample

CollectionExample.html

<template>
    <lightning-card title="Account Collection" icon-name="custom:custom14">
        <ul class="slds-list_ordered">
            <template for:each={accounts.data} for:item="account">
                <li key={account.Id}>
                    {account.Name}
                </li>
            </template>
        </ul>
    </lightning-card>
</template>

the above markup is iterating the data using the for:each directive as like below.

 <template for:each={accounts.data} for:item="account">

CollectionExample.js

import { LightningElement, track, wire } from 'lwc';

import getAccountContactList from '@salesforce/apex/AccountContactController.getAccountContactList';

export default class CollectionExample extends LightningElement {
    @wire(getAccountContactList) accounts; 
}

CollectionExample.js-meta.xml

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

Now push the component changes to scratch org and add this component to the record page. You can able to see the collection iteration data as shown below.

 

Nested Iteration using for:each directive

Now let us iterate the nested loop using the for:each directive .here is the example that will render the account and its contacts. Update the CollectionExample.html markup with the below code and push the changes to scratch org.

<template>
<lightning-card title="Account Collection" icon-name="custom:custom14">
<ul class="slds-list_ordered">
    <template for:each={accounts.data} for:item="account">
        <li key={account.Id}>
            {account.Name}
            <ul class="slds-list_ordered">
            <template for:each={account.Contacts} for:item="contact">
                    <li key={contact.Id}>{contact.Name}
                </li>
            </template>
        </ul>
        </li>
    </template>
</ul>
</lightning-card>
</template>

Push the change to scratch org and reload the page. Here is the final output.

 

Using Iterator directive

Iterator directive is another way to render the collection data. To apply a special behavior to the first or last item in a list, use the iterator directive, iterator:iteratorName={array}. Use iteratorName to access these properties:

  1. value—The value of the item in the list. Use this property to access the properties of the array. For example, iteratorName.value.propertyName.
  2. index—The index of the item in the list.
  3. first—A boolean value indicating whether this item is the first item in the list.
  4. last—A boolean value indicating whether this item is the last item in the list.

This sample code uses the same array as the previous example. To apply special rendering to the first and last items in the list, the code uses the first and last properties with the if:true directive. Update the  CollectionExample.html code with below code . in this example we will be displaying the list of accounts.

<template>
        <lightning-card title="Apex Iterator Example" icon-name="custom:custom14">
            <ul class="slds-m-around_medium">
                <template iterator:it={accounts.data}>
                    <li key={it.value.Id}>
                        <div if:true={it.first} class="list-first"></div>
                        {it.value.Name}
                        <div if:true={it.last} class="list-last"></div>
                    </li>
                </template>
            </ul>
        </lightning-card>
    </template>

CollectionExample.css 

.list-first {
    border-top: 1px solid black;
    padding-top: 5px;
}

.list-last {
    border-bottom: 1px solid black;
    padding-bottom: 5px;
}

Push the changes to scratch org and you can able to see these changes after reload.

Now let us see how to do the nested iteration using iterator directives . in this example we will be displaying accounts and its contacts. here is the HTML markup for the nested iteration.

<template>
        <lightning-card title="Apex Iterator Example" icon-name="custom:custom14">
            <ul class="slds-m-around_medium">
                <template iterator:it={accounts.data}>
                    <li key={it.value.Id}>
                        <div if:true={it.first} class="list-first"></div>
                        {it.value.Name}
                        <ul class="slds-m-around_medium">
                                <template iterator:it={it.value.Contacts}>
                                    <li key={it.value.Id}>
                                            <div if:true={it.first} class="list-first"></div>
                                            {it.value.Name} 
                                            <div if:true={it.last} class="list-last"></div>

                                   </li>
                                   </template>
                        </ul>
                        <div if:true={it.last} class="list-last"></div>
                    </li>
                </template>
            </ul>
        </lightning-card>
    </template>

 

Push the changes to the scratch org and reload the page. you can able to see the output as shown below and will be displayed account and its contacts.