Thursday, 24 June 2021

Salesforce CLI Unification

 Salesforce introduced a new global CLI executable called sf 

 that provides you with a single command line taxonomy for cross-Salesforce development.

 

 Salesforce CLI Unification unify all of Salesforce's product under one CLI.


 Salesforce CLI goal is to provide a seamless developer experience when building applications

 on any salesforce product as well as across products.


 CLI Unification is an effort designed to eliminate tool and context switching.

 

  ex :

  

  sf project deploy by default deploys the entire project that is defined in your local directory. 

  If your project includes Functions and a Force app, then both are deployed to their respective environments.

  

  Let’s say that you later include a Heroku app, some MuleSoft APIs, and a resource from Marketing Cloud in your project. 

  In this case, sf project deploy will deploy all of these resources to all of the respective environments.

  

  

  You can use the product-specific project deploy commands that have flag options for granular deployment.

  

  ex :

   sf project deploy org will support all the current options for force:source:deploy and force:source:push.

   

  To install the Demo CLI with npm, run the following from your terminal:

  

  npm install --global @salesforce/sf-demo

  sf --help 


  Usefull Commands : 

  

  sf --help         : shows the top-level topics and commands. 

  sf project --help : shows the subtopics and commands under project.

  

    sf config get

    sf config list

    sf config set

    sf config unset

    sf data data

    sf env alias set [ALIAS]

    sf env alias unset [ALIAS]

    sf env create compute [ENVNAME]

    sf env create org [ENVNAME]

    sf env display

    sf env list

    sf env log get

    sf env log list

    sf env log tail

    sf env logdrain add

    sf env logdrain list

    sf env logdrain remove

    sf env open

    sf env usage

    sf env var get

    sf env var list

    sf env var set

    sf env var unset

    sf event event

    sf generate analytics template

    sf generate apex class

    sf generate apex test

    sf generate apex trigger

    sf generate community

    sf generate function

    sf generate lightning component

    sf generate lightning event

    sf generate lightning interface

    sf generate project

    sf heroku heroku

    sf login

    sf login functions

    sf login org

    sf login org jwt

    sf logout

    sf logout org

    sf package package

    sf plugins

    sf plugins:inspect PLUGIN...

    sf plugins:install PLUGIN...

    sf plugins:link PLUGIN

    sf plugins:uninstall PLUGIN...

    sf plugins update

    sf project deploy

    sf project deploy functions

    sf project deploy org

    sf project retrieve

    sf project retrieve org

    sf reset

    sf run apex

    sf run function

    sf run function start

    sf test apex

    sf test function

    sf usage

    sf whoami

Tuesday, 22 June 2021

process a large amount of records in serial chunks using Queueables


/**

 * @description A demonstration recipe for how to process a large amount of

 * records in serial chunks using Queueables. The idea behind this recipe

 * is that Queueables, in production, have no max-queue depth. Meaning that so

 * long as you only enqueue one new queueable, it can keep cycling through until

 * the entire data set is processed. This is useful for instance, when you want

 * to process hundreds of thousands of records.

 *

 * Note: You're not able to re-enqueue within a test context, so the unit test

 * for this code is limited to the same number of records as chunkSize below.

 *

 * Note: This should be refactored to be an abstract class that you can extend

 * named 'Ouroboros'. (Ouroboros = the snake eating it's own tail)

 *

 * @group LDV Recipes

 */

public with sharing class LDVRecipes implements Queueable {

    private final Integer chunkSize = 20;

    private Id offsetId;

    private List<ContentDocumentLink> objectsToProcess;

    @testVisible

    private static Integer chunksExecuted = 0;


    /**

     * @description No param constructor. Use for starting the chain.

     */

    public LDVRecipes() {

        this.objectsToProcess = getRecordsToProcess(this.offsetId);

    }


    /**

     * @description    Constructor accepting an ID to use as an offset. Use

     * this version to *continue* the chain.

     * @param offsetId

     */

    public LDVRecipes(Id offsetId) {

        if (offsetId != null) {

            this.offsetId = offsetId;

        }

        this.objectsToProcess = getRecordsToProcess(this.offsetId);

    }


    /**

     * @description            This method contains the 'what' happens to each

     * chunk of records. Note, that this example doesn't actually do any

     * processing. In a real-life use case you'd iterate over the records stored

     * in this.objectsToProcess.

     * @param queueableContext

     */

    public void execute(System.QueueableContext queueableContext) {

        // Used to demonstrate the method was executed.

        LDVRecipes.chunksExecuted += 1;

        // If you're processing the group of records there's likely a better way

        // to determine the last objects' id, but this will do for demonstrating

        // the idea. We need the last id from objectsToProcess in order to

        // construct the next queueable with an offset.

        Id lastRecordId = objectsToProcess[objectsToProcess.size() - 1].id;


        if (getRecordsToProcess(lastRecordId).size() > 0 && safeToReenqueue()) {

            LDVRecipes newQueueable = new LDVRecipes(lastRecordId);

            System.enqueueJob(newQueueable);

        }

    }


    /**

     * @description    Returns a 'cursor' - a set of records of size X from a

     * given offset. Note: We originally intended to use OFFSET - the SOQL

     * keyword, but discovered the max OFFSET size is 2000. This obviously won't

     * work for large data volumes greater than 2000 so we switched to using the

     * ID of the record. Since ID is an indexed field, this should also allow

     * us to prevent full table scans even on the largest tables.

     * @param offsetId The offset id is used to demarcate already processed

     * records.

     * @return         `List<ContentDocumentLink>`

     */

    private List<ContentDocumentLink> getRecordsToProcess(Id offsetId) {

        String queryString = '';

        queryString += 'SELECT ContentDocumentId,ContentDocument.Title, ContentDocument.CreatedDate,LinkedEntityId ';

        queryString += 'FROM ContentDocumentLink ';

        queryString += 'WHERE LinkedEntityId in (SELECT Id FROM Account) ';

        if (offsetId != null) {

            queryString += 'AND ID > :offsetId ';

        }

        queryString += 'WITH SECURITY_ENFORCED ';

        queryString += 'ORDER BY ID ASC ';

        queryString += 'LIMIT :chunkSize';

        return Database.query(queryString);

    }


    private Boolean safeToReenqueue() {

        return Limits.getLimitQueueableJobs() > Limits.getQueueableJobs();

    }

}

Monday, 21 June 2021

Salesforce Integration API's

No-code Integrations :

=====================


MuleSoft

Salesforce Connect

Heroku Connect

External Services


Custom API Integrations :

=========================


SOAP

REST

Bulk

Composite

Streaming 

metadata

Tooling 

UI


Streaming Events Integrations (pub/Sub) :

=========================================


Platform Events

Change Data Capture


Salesforce Platform Integration Features :


1.Salesforce Core


APIs and Web Services

Salesforce Connect

External Services

Event Bus


2.Heroku 


Database

Heroku Connect

Other add-ons

Compute Dynos


3.Mulesoft Anypoint


Connectors

API Design & Mgt

Integration Runtime

Secure API Gateway


Salesforce Core APIs :

======================

1.REST API

  Access and manipulate data with a RESTful pattern using JSON and XML.

2.SOAP API

  Access and manipulate data using standard SOAP XML messages

3.Bulk API

   Perform large volume CRUD operations asynchronously.

4.Composite Graph API

   Chain multiple operations for related objects/records in a single REST call.

5.APEX (Custom SOAP and REST API using Apex Programming language)

   Build custom SOAP and REST APIs through Apex programming language.

6.Streaming API

   Subscribe to events using the Bayeux/CometD HTTP long-polling protocol.

7.User Interface API.

   Return UI-optimized payload display,edit or create a record.

8.Industries API

   Access to special Health and Financial Services Cloud-specific objects and features.

9.Analytics API

  Access Salesforce Report and Dashboard data using Restful APIs.

10.Metadata API

   Package and deploy setup metadata to Salesforce orgs asynchronously.

11.Tooling API

   Build custom development tools for applications using SOAP and RESTful APIS.

12.Social API 

   View,create and join Chatter conversations through RESTful APIs

   


Data APIs(SOAP & REST) :


Access and modify objects and records in real-time


ex : /SObjects/Account

     /SObjects/Account/describe

     /query?q=SELECT+Name,Industry+FROM+Account

     

     /SObjects/Property__c

     /SObjects/Property__c/describe

     /query?q=SELECT+Name,Type__c+FROM+Property__c

     /query?q=SELECT+FIELDS(ALL)+FROM+Property__c+LIMIT+200

     

Bulk API :


Access and modify large number of records asynchronously.

SOAP & REST are real-time APIs so daily limits apply.

Bulk API lets you process up to millions of records asynchronously.

Based on REST,Processes operations in batch.


Configure and start --> Check job Status --> Retrieve results.


Composite Graph API :


Chain multiple CRUD operations for related objects/records in a single REST call.

Requests organized in a graph.

Designed for optimal processing.

Ability to roll back entire transaction.


Apex Callout (HTTP Request) :


HttpRequest req=new HttpRequest();

req.setEndpoint(url);

req.setMethod(method);

req.setBody(body);

Http http =new Http();

HttpResponse resp=http.send(req);


Custom Apex REST Endpoint :


@RestResource(urlMapping='/propertyhub/*)

global class PropertiesService{

  @HttpGet

  global static void getAccounts(){

    RestRequest req = RestContext.request;

    RestResponse res = RestContext.response;

    

    //Do something with request

    // Send a custom response or return data (serialized as JSON)

      try {

            List<Account> accounts = [SELECT Id, Name FROM Account];

            res.responseBody = Blob.valueOf(JSON.serialize(accounts));

            res.statusCode = 200;

        } catch (Exception e) {

            res.responseBody = Blob.valueOf(e.getMessage());

            res.statusCode = 500;

        }

  

  }

 

}     


Design with the Right API :


SOAP : server to server , real-time access

REST : Client to Server, real-time access

Bulk : Working asynchronously with large data volumes

Composite API : Set of operations related objects/records

Custom APex REST & SOAP : Exposing custom business logic.


Salesforce Connect :


1.OData 2.0/4.0 or Custom Connector using Apex.

2.External data represented as Salesforce entites/objects.

3.Setup & sync with no code.

4.No data duplication

5.Data mastering at system of record.


Heroku Connect :


Salesforce data synchronized to a Heroku Postgres database.


External Service :


Integrate with 3rd party systems without code.

1.Import an ApenAPI specification schema.

2.Select operations

3.Use auto-generated Flow Actions.


Streaming API :


1.Change Data Capture(streaming event)

2.Platform Events


1.Change Data Capture(streaming event) :


A Change Data Capture event, or change event, is a notification that Salesforce sends 

when a change to a Salesforce record occurs as part of a create, update, delete, or undelete operation. 

The notification includes all new and changed fields, and header fields that contain information about the change. 

For example, header fields indicate the type of change that triggered the event and the origin of the change. 

Change events support all custom objects and a subset of standard objects.


Use change events to:


1.Receive notifications of Salesforce record changes, including create, update, delete, and undelete operations.

2.Capture field changes for all records.

3.Get broad access to all data regardless of sharing rules.

4.Get information about the change in the event header, such as the origin of the change, 

  which allows ignoring changes that your client generates.

5.Perform data updates using transaction boundaries.

6.Use a versioned event schema.

7.Subscribe to mass changes in a scalable way.

8.Get access to retained events for up to three days.


Asynchronous Apex triggers :


Asynchronous Apex triggers are change event triggers that run asynchronously after a database transaction is completed. 

They are ‘after-insert’ triggers and can be created the same way you create regular Apex triggers, the only difference is the sObject,

where you will have change it to the event object. The name of changeEvent object has suffix “changeEvent” for standard object and   

__changeEvent for custom objects (e.g. OpportunityChangeEvent , Employee_ChangeEvent  etc).


Use of Asynchronous trigger and Change Data Capture. 


1. Asynchronous triggers are the probable replacement for future methods and queuable 

    jobs with certain limitations.  


2. Let’s take a simple business example: when a customer logs a case with customer 

    service, case records gets created. If you want write a logic which can execute 

    asynchronously and assign a technician to it then you can write an asynchronous trigger 

    on CaseEvent.


3. Change Data Capture can be used for Integration purpose such as to downstream 

    system (ERP System) and it is much more effective and faster than the normal 

    webservices.  


4. CDC stores events up to 3 days so very effective if your downstream system is down for 

     weekly maintenance, it will automatically re trigger once it is up.  


2.Platform Events :


Platform events enable you to deliver secure, scalable, and customizable event notifications within Salesforce 

or from external sources via a Message bus.


MuleSoft :


Build Low Code Integrations with MuleSoft.


Integrate fast with Flow Designer.

Rich set of built-in connectors.

Low code be extended with script.

More than just a builder, a run-time manager.


Sunday, 13 June 2021

Multi-Currency in Salesforce

 1.Currency controls display of currency, such as currency symbols, period/comma for decimal places.

2.All objects that have currency field will have CurrencyIsoCode field to specify the currency that is used (available in multi-currency org)

3.In SOQL, convertCurrency() function can be used to convert currency and format() function 

can be used in SOQL to format number, date, time, fields based on user's locale, 

ex: SELECT format(convertCurrency(Amount)) from Opportunity

Saturday, 12 June 2021

Canvas app in Salesforce

 Canvas allows developers to connect existing legacy system or any web-based application with Salesforce

using javascript and REST API.Canvas applications can be displayed in chatter,Salesforce Mobile Cards or Visualforce Page.


ex :


<apex:page controller="JSONGeneratorSample">

    <apex:canvasApp developerName="mycanvas" parameters="{!generateJSON}" />

</apex:page>


<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes" access="global" >

    <div class="canvas-container">

        <force:canvasApp developerName="mycanvas" height="1200px"/>

    </div>

</aura:component>



Canvas App in Salesforce :


Canvas enables you to easily integrate a third-party application in Salesforce.

Canvas is a set of tools and javascript APIs that you can use to expose an application as a canvas app.

This means you can take your new or existing applications and make them available to your users as part of their Salesforce experience.


Canvas App Previewer :


Canvas App Previewer is a development tool that lets you see what your canvas apps will look like before you publish them.


Note :

The third-party app that you want to expose as a canvas app can be written in any language.

The only requirement is that the app has a secure URL (HTTPS).


Important Entity :


1.Authentication

2.Context

3.Cross-domain XHR

4.Events

5.Canvas Apps in Visualforce


canvas app is also a kind of connected app.you can consider canvas app as connected app 

with some enhanced features to make it work seamlessly with external apps within Salesforce UI.

Some of these additional features are :


1.canvas app settings has 'Access Method' option which simplifies the way your connected app is 

getting authenticated and authorized. This is important when you want to have your canvas app do 

aurhentication and authorization behind the scene without having user know about it.


2.Canvas app frameowork provides LightWeight and easy-to-use javascript libraries.


3.Canvas app frameowork natively provides 'Context Services' which tells more about the logged-in user,

what org are they in,how much area does the canvas provide to display etc.


4.It natively allows cross-domain API calls.


5.It is based on lightweight JSON eventing frameowork which allows your app to publish and 

subscribe to events.(the events are sent through Canvas API).


Important Parameters :


Authentication - signed request or OAuth 2.0.

Context

Cross-domain cross-domain XML HTTP requests

Resizing -M

Events - Events prvide a javascript-based way to send and receive events between canvas apps.

Canvas Apps in Aura

Canvas Apps in Visualforce

Canvas Apps in the publisher

Canvas Apps in the Chatter Feed

Canvas in the Salesforce Mobile App


Canvas can be placed in Salesforce :


1.Chatter feed

2.Chatter tab

3.Console

4.Visualforce Page 

5.Layouts and Mobile Cards

6.Mobile Nav

7.Open CTI

8.Publisher


Authentication and Permission :


1.Permission

"Customize Application"

"Modify All Data"

2.Authentication

1.Signed request

2.Oauth2.0



How does canvas work ?


1.User clicks on the application from a chatter tab or Visualforce Page.

2.A signed Post request is sent to the external application.

3.External application decodes signed request,obtaining canvasRequest object.

4.External application returns HTML that is loaded into the Salesforce UI.

5.User interacts with external application page within Salesforce.

6.External application page calls out to containing frame's javascript SDK.containing page calls Salesforce.

7.External application interacts through standard APIs.


Note :

1.Canvas apps are loaded into salesforce through an iframe.

2.with canvas you can use a secure communication protocol via javascript to communicate with salesforce.


Access method :


The Force.com Canvas Framework provides authentication into salesforce.


1.Signed Request(POST)

2.OAuth Webflow (GET)


CanvasLifecycleHandler:


Note :

Apex LifeCycle Handler : Controlling your Force.com Canvas context.


Customizing the Canvas Signed Request :


Signed Request : Delivering Context to your App.

The signed request is the default (and recommended) access method.


when you click the Canvas app, we Post a signed equest to your endpoint.

Context contains data like :


1.Client information

  OAuth Token,Refresh Token,Oauth login URLs

2.User Information 

  Name,Username,ID,Email etc

3.Organization Information 

   Name,ID,MNamespace etc.

4.Environment Information 

   Dsiplay Location,Dimensions,Parameters,Record info etc.

5.Version Information

6.Useful Links


Controlling Signed Request using CanvasLifecycleHandler :


1. Using Apex to control your signed request.

2.Apex class is associated with the Canvas App.

3.You can control

-> Remove certain Signed Elements.

-> Customizing Parameters/Customize Record Fields.

-> Customizing the Canvas URL

-> Custom Error Handling

   

ex 

public class MyCanvasListener implements Canvas.CanvasLifecycleHandler{

    

    public Set<Canvas.ContextTypeEnum> excludeContextTypes(){

       Set<Canvas.ContextTypeEnum> excluded = new Set<Canvas.ContextTypeEnum>();

        excluded.add(Canvas.ContextTypeEnum.ORGANIZATION);

        excluded.add(Canvas.ContextTypeEnum.USER);

        excluded.add(Canvas.ContextTypeEnum.RECORD_DETAIL);

        return excluded;

    }

    

    public void onRender(Canvas.RenderContext renderContext){

    

        Canvas.ApplicationContext app = renderContext.getApplicationContext();

        Canvas.EnvironmentContext env = renderContext.getEnvironmentContext();

        Double currentVersion = Double.valueOf(app.getVersion());

        if (currentVersion <= 5){

            throw new Canvas.CanvasRenderException('Error: Versions earlier than 5 are no longer supported.');

        }

        app.setCanvasUrlPath('/alternatePath');

        env.addEntityFields(new Set<String>{'Name','BillingAddress','YearStarted'});

        Map<String, Object> previousParams =(Map<String, Object>) JSON.deserializeUntyped(env.getParametersAsJSON());

        previousParams.put('newCustomParam','newValue');

        env.setParametersAsJSON(JSON.serialize(previousParams));

        

    }

}  


Custom Error Handling :


with the apex lifecycle handler, you can inject your own error handling.


-> Error handling logic exists inside of the apex class.

-> Error is displayed in the Canvas error handling framework.

Friday, 11 June 2021

Lightning Web Component quick actions

 Two different types of LWC Quick actions

1.Screen Actions

2.Headless Actions


Screen Actions :


Traditionally, when you click on an action in Salesforce, it will open up a modal window that you can use to display data or interact with data. 

This is exactly what you get when you are creating a Screen Action. 

You are able to take any Lightning Web Component that you have created and expose it as a quick action.


ex :

//my-action.html


<template>

</template>


//my-action.js


import { LightningElement, api } from 'lwc';

 

export default class MyAction extends LightningElement {

  @api invoke() {

    console.log('Hello, world!');

  }

}


//my-action.js-meta.xml


<targets>

  <target>lightning__RecordAction</target>

</targets>

<targetConfigs>

  <targetConfig targets="lightning__RecordAction">

    <actionType>ScreenAction</actionType>

  </targetConfig>

</targetConfigs>


Headless Actions :


Headless actions are a welcome addition to LWC capabilities. They allow you to run JavaScript directly from the click of a button through a 

Headless Lightning Web Component. This may sound familiar if you recall writing JavaScript buttons in the past. 

One of the key differences between a screen action and a headless action is that you don’t need the HTML file in your LWC.


ex :


//headless-action.js


import { LightningElement, api } from 'lwc';

 

export default class MyAction extends LightningElement {

  @api invoke() {

    console.log('Hello, world!');

  }

}


//headless-action.js-meta.xml


<targets>

  <target>lightning__RecordAction</target>

</targets>

<targetConfigs>

  <targetConfig targets="lightning__RecordAction">

    <actionType>Action</actionType>

  </targetConfig>

</targetConfigs>


Note : 

LWC Quick actions are currently only available for use on Lighting Record Pages.


Lightning Quick Action Panel :


By default, an LWC Screen Action does not have the header and footer that you normally see in a modal window. 

This gives you the opportunity to create heavily customized user interfaces. However, if you would like to create a consistent experience, 

there is a new base component for doing just that, The Lightning Quick Action Panel.


ex :


 <template>

  <lightning-quick-action-panel title="Quick Action Title">

    Body Content

    <div slot="footer">

      <lightning-button variant="neutral" label="Cancel"></lightning-button>

      <lightning-button variant="brand" label="Save"></lightning-button>

    </div>

  </lightning-quick-action-panel>

</template>


This component allows you to:


1.Set the title attribute of the component to render the title in the modal header.

2.Place the content of your action in the body.

3.Use a slot to place content in the modal footer.


Close Action Screen Event :


When you are using screen actions, you can close the modal by importing the new CloseActionScreenEvent from 'lightning/actions'.

When fired this will shut the model window if the user needs to cancel or close the quick action.


ex :

  import { CloseActionScreenEvent } from 'lightning/actions';

 

closeAction(){

  this.dispatchEvent(new CloseActionScreenEvent());

}


Headless Actions :


A headless action can be invoked by creating an invoke() method that is exposed publicly with an @api decorator. 

This is called each time the Quick Action’s button is clicked. The component is inserted into the DOM right when the record page 

is rendered so you cannot rely on any of the standard lifecycle hooks for executing the action. For example, the connectedCallback() 

is run right when the record page loads.


It is important to note that headless actions do not have the ability to prevent the user to double-click the action. 

The following code sample will show you how you can make the invoke() method asynchronous to prevent it from being called twice.

  


ex :


import { LightningElement, api } from "lwc";

 

export default class HeadlessAsync extends LightningElement {

    isExecuting = false;    

    @api async invoke() {

        if (this.isExecuting) {

            return;

        }  

        this.isExecuting = true;

        await this.sleep(2000);

        this.isExecuting = false;

    }  sleep(ms) {

        return new Promise((resolve) => setTimeout(resolve, ms));

    }

}


Wednesday, 9 June 2021

The Four Streaming APIs in Salesforce

 1.Generic events

2.Push Topic events

3.Platform Events

4.Change Data Capture events


These four Streaming APIs are part of what we call the Enterprise Messaging Platform (EMP).


Generic and PushTopic came as the "first generation", then Platform Events and Change Data Capture came second generation. 

While the first generation of APIs is quite mature now, it is not evolving as much as the second one.


A Shared Model :



All Streaming APIs are built on the same core technology:CometD.

This technology relies on a messaging bus that offers a publish/subscribe mechanism for events.


The publish/subscribe model follows the following scenario:


1.Event consumers connect to the messaging bus and subscribe to specific channels (event types)

2.Event producers connect to the bus and publish an event on a channel

3.The bus broadcasts the event to all registered subscribers


This means that the message producer is fully decoupled from the consumers. This model allows to build event-driven architectures at scale.

Typical use cases for this are system integrations and real-time apps.


1.Generic 


Data Structure    : Unstructured (String)

Publication       : REST API

Subscription      : code 


2.PushTopic  


Data Structure    : Defined by target sObject retrieved via a SOQL query

Publication       : Automated

Subscription      : code


3.Platform Events 


Data Structure    : Custom typed fields

Publication       : Delarative or Code

Subscription      : Delarative or Code


4.Change Data Capture 


Data Structure    : Defined by target sObject

Publication       : Automated

Subscription      : Delarative or Code


Streaming API provides two types of events that you can publish and subscribe to : PushTopic and generic.


PushTopic events track field changes in Salesforce records and are tied to Salesforce records.

Generic events contains arbitrary payloads.


Streaming API :


Streaming APIs enables transmitting of real data from Salesforce Platform.

Transmission of data done using push technology.

Push technology transfers information that is initiated from a server to the client.

Provides a subscription mechanism for receiving events in near real time.

Push technology also called the publish/subscribe model.


Pull Technology :


1.Client request data from the server periodically.

2.Clients poll the server for data updates, and freshness of data depends on the poll frequency.

3.Clients can make excessive calls and cause server slowdown.


Push Technology :


1.Notifications are sent to the subscriber in real time.

2.No pooling required.


Mechanism of Streaming API :


To enable Publisher/Subscriber model, active connection is required between Salesforce and each client.


Short Polling :


Client keeps sending to make active connection.


Long Polling :


1.Clients send requests for information but with the expectation the server may not respond immediately.

2.Server respond when data is changed for object.

3.Long polling supported using Bayeux Protocol or CometD.


Push Topic :


PushTopic events provide a secure and scalable way to receive notifications for 

changes to Salesforce data that match a SOQL query you define.


1.Receive notifications of Salesforce record changes ,including create,update delete and undelete.

2.Capture changes for the fields and records that match a SOQL query.

3.Recieve change notifications for only the records a user has access to based on sharing rules.


ex :


PushTopic pushTopic = new PushTopic();  

pushTopic.Name = 'AccountPush';  

pushTopic.Query = 'SELECT Id, Name, Type, Phone, Website  FROM Account WHERE Active=\'Yes\'';  

pushTopic.ApiVersion = 48.0; 

pushTopic.NotifyForOperationCreate=true; 

pushTopic.NotifyForOperationUpdate=true;

pushTopic.NotifyForOperationUndelete=true;

pushTopic.NotifyForOperationDelete=true;

pushTopic.NotifyForFields='Referenced';

insert pushTopic; 


Note :

NotifyForFields is used to determine when ontification should be sent.

NotifyForFields in PushTopic values.


All,Referenced(default),Select,Where


1.All - considers changes in all fields.

2.Referenced - consider changes in fields in both SELECT and WHERE clauses.

3.SELECT - considers changes in fields in SELECT clause.

4.WHERE - considers chnages in fields in WHERE clause.


PushTopic Security :


1.To receive notification user must have access to object.

2.Field Level Access required.

3.Only record where user has access will be returned.


Considerations - Multiple Notifications in Same Transaction :


1.Streaming API notifications sent in Reverse Order Within a Trasaction:


In general, event notifications are delivered in the order of record changes.


When a record triggers multiple notifications within the same transaction, the last 

notifications are delivered first.


2.Multiple Streaming API Notifications for the Same Record and Untracked Fields :


If field change triggers other changes on the same record, more notifications are sent for those fields.


3.Only Last PushTopic Notification Sent for the Same Record


When multiple PushTopic notifications are generated for the same record within 

about one millisecond and in the same transaction,only the last notification is sent.


LIMITS :


Maximum number of topics (PushTopic records) per org

UE: 100 EE: 50 All other editions: 40


Maximum number of concurrent clients (subscribers) across all channels and for all event types

UE: 2000 EE: 1000 All other editions: 20


Maximum number of delivered event notifications within a 24-hour period, shared by all CometD clients

UE: 1000000 EE: 200000 All other editions: 50000 (10000 for free orgs)


Socket timeout during connection (CometD session)

UE : 110 seconds EE: 110 seconds All other editions: 110 seconds


Timeout to reconnect after successful connection (keepalive)

UE : 40 seconds EE : 40 seconds All other editions: 40 seconds


Maximum length of the SOQL query in the Query field of a PushTopic record

UE : 1300 characters EE : 1300 characters All other editions: 1300 characters


Maximum length for a PushTopic Name

UE: 25 characters EE: 25 characters All other editions: 25 characters



You can use the following queries to review the usage

SELECT count() FROM PushTopic

SELECT count() FROM PushTopic WHERE IsActive = true



Generic Events :


Use generic events to send custom notifications that are not tied to Salesforce data changes.


1.Publish and receive arbitrary payloads in JSON without a predefined event schema.

2.Broadcast notifications to a target set of users,specific teams,or your entire org.

3.Send notifications for events that are external to salesforce.


How to use Generic Events ?


1.Streaming Channel


A StreamingChannel that defines the channel, with a name that is case-sensitive.

It is object and can be accessed from app menus


2.Clients


one or more clients subscribed to the channel.


3.Streaming Channel Push REST API


Streaming Channel Push REST API to monitor and invoke push events on the channel.

Monday, 7 June 2021

Heroku Connect

 Heroku Connect provides a way to synchronize Salesforce data with a Heroku Postgres database making it available to 

customer-facing apps on Heroku.


Data Integration as a service.

Data replication and data virtualization across Salesforce and Heroku Postgres.


Heroku Connect has a great way to archive your Salesforce data in a way that still maintains

in a way that's accessible still within Salesforce so you have archived it but you can still 

see it in Salesforce very powerful it can be a big efficiency and cost saver for you and 

business intelligence so you have all of this customer information in salesforce 

but you're interested in harnessing it and integrating to external data 

warehouse or analytic systems that you may be managing who can connect is a great tool for 

this as well.


Note :

Force.com is for enterprise applications and Heroku id for customer facing apps built with open source stacks.


Heroku Connect features include :


1.Ability to access Salesforce data via SQL

2.Optimized Force.com API intercations

3.Performance and scale

4.Set it and forget it simplicity 


Sunday, 6 June 2021

Remote Action in Salesforce

 Remote Action is a way to access Apex method using Javascript in your Visualforce page.

It allows you to create pages with complex, dynamic behavior that isn’t possible with the standard Visualforce AJAX components.


Remote action method should always have the @RemoteAction annotation and it should be Static.


public with sharing class CasePriority {

    @RemoteAction

    public static list<Case> getCases(string priority) {

        list<Case> cases = [Select Id, CaseNumber, Subject, Description, Priority, Status 

                              From Case 

                              Where Priority = :priority

                              And Status = 'New'

                              Limit 5];

        if (cases.isEmpty()){

            return new list<Case>();

        }

        return cases;

    }

}


ex :



<apex:page controller="CasePriority" lightningStylesheets="true">

    <script type="text/javascript">

    function getCases(priority) {

        Visualforce.remoting.Manager.invokeAction(

            '{!$RemoteAction.CasePriority.getCases}', priority,

            function(result, event){

                if(event.status){

                    var html = '<table>';

                    html += '<tr><th>Case Number</th><th>Subject</th><th>Priority</th></tr>';

                    result.forEach(function(item){

                        html += '<tr>';

                        html += '<td>'+ item.CaseNumber +'</td>';

                        html += '<td>'+ item.Subject +'</td>';

                        html += '<td>'+ item.Priority +'</td>';

                        html += '</tr>';

                    })

                    html += '</table>';

                    document.getElementById('results').innerHTML = html;

                }           

            },

            {escape: true}

        );

    }

    </script>

    

    <apex:pageblock id="block">

        <apex:pageblockbuttons location="top" >

            <apex:form>

            <apex:commandButton value="High" onclick="getCases('High'); return false;" />

                <apex:commandButton value="Medium" onclick="getCases('Medium'); return false;"/>

                <apex:commandButton value="Low" onclick="getCases('Low'); return false;"/>

            </apex:form>

            

        </apex:pageblockbuttons>

        

        <apex:pageblocksection columns="1" id="blockSection">

            <div id="results">

                

            </div>

        </apex:pageblocksection>

    </apex:pageblock>

</apex:page>


Notes :


1.@RemoteAction annotation is mandatory

2.Remote Action methods should always be static

3.If you are using the Visualforce Page inline in a Page Layout, then the method should be declared as global instead of public.



Key Features are: 


1.Remote Action is a static method

2.Bandwidth Usage is less

3.View state is not maintained

Invalid Cross Reference Id Error

 Getting the “Invalid Cross Reference Id” Salesforce error and unsure what it means? 

If so, that error means that the Salesforce Id used in a lookup or master-detail relationship field is not valid.


Causes


1) Wrong Object Type – The relationship field is being set to the Salesforce Id of the wrong object. 

For example, if field A is a lookup to the Account object, an opportunity Id can’t be used in this field.


2) Record Deleted – The record no longer exists. This can happen if someone deleted the record while a user 

or the system is inserting or updating records. It can also happen during a request when the record is initially inserted 

but then rolled back so the code still has a reference to the record with an id in memory but the record does not exist in the database.


3) Relationship Field Pointing To Wrong Object – This happens less frequently but is still a cause of this error. 

Sometimes, there are multiple objects in the system with the same name and a user chose the wrong object to have the lookup or master-detail point to. 

This happens because Salesforce will show the same object name without any further detail in the object list when defining the field 

so it’s not immediately clear which to choose.


To choose the correct object when there are multiple with the same name, inspect the drop down list in the browser 

and view the values for the select list items. Identify the correct one to use and then choose it from the drop down list.

Wednesday, 2 June 2021

Salesforce Lightning Inspector

 The Salesforce Lightning Inspector opens up and improves your Lightning Component developement,

giving you access to a wealth of data about your running applications and components.


With the Lightning Inspector you can :


1.Easily inspect and navigate the structure of your components.

2.Identify performance bootlenecks by looking at a graph of comonent creation time.

3.Debug server interactions faster by monitoring and modifying responses.

4.Navigate the component tree, inspect components and their associated DOM elements.

5.Track event firing and handling sequences. 


Use Chrome Developer Tools to debug Lightning Components.

Install the 'Salesforce Lightning Inspect' which is available in Google Chrome extension.


The Lightning Tab includes several sub tabs, which each reveal more detailed information about your component.


1.Component Tree Tab

2.Performance Tab

3.Transactions Tab

4.Event Log Tab

5.Actions Tab

6.Storage Tab


Component Tree Tab :


The Component Tree shows you a detailed tree view of the structure of your components.

The Component tree shows you the actual components themselves and gives you information about the attributes they use.


Performance Tab :


Using the Performance tab in the Salesforce Lightning Inspector, we can isolate inspection to just the component code,

allowing us to identify which components are slower and locate where in the component hierarchy the slowness occurred.


This can be especially useful when you have a slow performing Lightning Page with several components.

You can use the chart to visualize the performance of each component and then spot pretty easily any outliers.


Transaction Tab :


Using the Transactions tab,we can see the recorded state(s) during portions of the application's execution.

The transaction data includes the amount of XHR's(XMLHttpRequest) that were sent,

the actions that were called,the time those actions took.


Event Log Tab :


1.CMP events

2.APP events

3.unhandled events


With the Event Log Tab , we can follow along and inspect the events being triggered either by code or user interaction.


You can easily spot whether the event was a component or an app event by looking for CMP or APP below the event.

And there are buttons that let you filter for either one , as well as unhandled events.


Expanding out the event will reveal very useful information such as the parameters,

caller,source,duration and call stack.


You can also click the Toggle Grid button to toggle on or off a diagram of the event.

This can be very useful when you have a page with multiple components and you are not 

sure which component fired which event.


Action Tab :


This is my favorite tab and one I use the most. Toggling on the recording will show you actions sorted 

according to whether they are pending, running, or completed. The view defaults to show all actions, 

but you can narrow down the list by using the filter buttons at the top. This can be useful for quickly zeroing 

in on an error since most pages will produce a lot of actions.


Storage Tab :


The Storage tab reveals the client-side storage for Lightning applications. Actions marked as storable are cached in the actions store. 

When a storable action is run it will use the value from the actions store if available. This can avoid a server trip altogether 

making your component run much faster. Using the storage tab you can see which actions are cached, the size of each cached action, 

and even where the cache lives.


(or)


The storage tab shows you the client-side storage size of any storable actions your page may use.

It will also show the specific items contained in storage.

Communication Patterns for Lightning Web Components

 1.Passing data down the component hierarchy.

2.Passing data up the component hierarchy.

3.Passing data to components that share no common ancestry.


1.Passing data down the component hierarchy :


There are three techniques for passing data from a parent to a child component.


a.Public Property

b.Public getters and setters

c.Public methods



Public Property :


A public property is exposed by applying the @api decorator on a class property of a child component.

This lets the parent component assign a value to it in two different ways.

Either via a custom HTML attribute or dynamically with javascript.


Note : public properties are reactive so the component re-rnders whenever one of its public properties is updated.

On the downside, you cannot run custom logic when the value changes and the child component should not assign values 

to its public properties.


ex :


// parentComponent.html 


<template>

 <div class="slds-var-m-around_medium">

     <c-child-component

      child-attribute={valueToSet}>

     </c-child-component>

     

      <lightning-button variant="brand" label="Set Value" title="Set Value" onclick={handleClick} class="slds-m-left_x-small"></lightning-button>

 </div>

</template>


// ParentComponent.js


import { LightningElement,track } from 'lwc';


export default class ParentComponent extends LightningElement {

   @track valueToSet;  

   

     connectedCallback(){

       //setting property value

        this.valueToSet = "someValue";

     } 


     handleClick(event) {     

        this.template.querySelector('c-child-component').childAttribute="someValue";

     }     

}


// childComponent.html 


<template>

 <lightning-card title="Public Property" icon-name="standard:product_consumed">

    {childAttribute}

 </lightning-card>

</template>


// ChildComponent.js


import { LightningElement,api } from 'lwc';


export default class ChildComponent extends LightningElement {

   @api childAttribute;   

}



Public getters and setters :


Public getters and setters behave exactly like public properties when used in a parent component. 

However, they bring additional flexibility to the child component by allowing you to execute custom logic when retrieving or updating a value. 

Additionally, a child component is able to set values using its own setters.


Another important difference with public properties is that getters and setters don’t provide persistence out of the box. 

A common pattern to handle that is to use a “private” property prefixed with an underscore to store the value internally in the child component.


Here’s an example of how a parent component uses a childAttribute public setter from a child component and saves 

its value in a _childAttribute property:


ex :


// parentComponent.html 


<template>

 <div class="slds-var-m-around_medium">

     <c-child-component

      child-attribute={valueToSet}>

     </c-child-component>

     

      <lightning-button variant="brand" label="Set Value" title="Set Value" onclick={handleClick} class="slds-m-left_x-small"></lightning-button>

 </div>

</template>


// ParentComponent.js


import { LightningElement,track } from 'lwc';


export default class ParentComponent extends LightningElement {

   @track valueToSet;  

   

     connectedCallback(){

       //setting property value

        this.valueToSet = "someValue";

     } 


     handleClick(event) {     

        this.template.querySelector('c-child-component').childAttribute="someValue";

     }     

}


// childComponent.html 


<template>

 <lightning-card title="Public Getters and Setters" icon-name="standard:product_consumed">

    {childAttribute}

 </lightning-card>

</template>


// ChildComponent.js


import { LightningElement,api } from 'lwc';


export default class ChildComponent extends LightningElement {


   _childAttribute;   

   

   @api

   get childAttribute(){

        return this._childAttribute;

         

    } 

    set childAttribute(value){

      // Extra Processing goes here 

       this._childAttribute = value;

    }

}


Public Methods :


You may call public methods to pass several values to a child component in order to perform an action like a calculation. 

As opposed to setters, methods allow you to enforce consistency by passing multiple parameters at once.


ex :


// parentComponent.html 


<template>

 <div class="slds-var-m-around_medium">

     <c-child-component>

     </c-child-component>     

      <lightning-button variant="brand" label="Set Value" title="Set Value" onclick={handleClick} class="slds-m-left_x-small"></lightning-button>

 </div>

</template>


// ParentComponent.js


import { LightningElement,track } from 'lwc';


export default class ParentComponent extends LightningElement {

    

     handleClick(event) {     

        this.template.querySelector('c-child-component').getDataFromParent("someValue1","someValue2");

     }     

}


// childComponent.html 


<template>

 <lightning-card title="Public Method" icon-name="standard:product_consumed">

    {childAttribute1}

    {childAttribute2}

 </lightning-card>

</template>


// ChildComponent.js


import { LightningElement,api } from 'lwc';


export default class ChildComponent extends LightningElement {


    childAttribute1;  

    childAttribute2;   

   

   @api

   get getDataFromParent(value1,value2){

         this.childAttribute1=value1;

         this.childAttribute2=value2;         

    } 

   

}


Note :


Unlike public properties or setters, methods are not exposed in the component’s HTML tag. 

They can only be called with JavaScript. This can be a limitation if you need to call a method in a reactive way (whenever some values change). 

Likewise, calling a method won’t automatically trigger a re-render on the target component. 

The component only re-renders if the method modifies properties used in the component’s template.


Methods support asynchronous processing as they can return any type of value including promises


2.Passing data up the component hierarchy:


You can pass data from a child component to a parent or ancestor with events. 

Lightning Web Components relies on DOM events (as defined in the standard DOM specification) to propagate data up the component hierarchy.


ex :


// parentComponent.html 


<template>   

 <c-child onselect={handleSelect}></c-child>

</template>



// ParentComponent.js


import { LightningElement,track } from 'lwc';


export default class ParentComponent extends LightningElement {

    @track contactId

    

     handleSelect(event) {   

        const conId=event.detail;     

        this.contactId=conId;

     }     

}


// childComponent.html 


<template>

    <lightning-button onclick={handleClick} label="fireEvent"></lightning-button>

</template>


// ChildComponent.js


import { LightningElement} from 'lwc';


export default class ChildComponent extends LightningElement {


    handleClick(event){

      // Creates the event

        const selectedEvent = new CustomEvent('select', {detail : contactId});

        //dispatching the custom event

        this.dispatchEvent(selectedEvent);        

    } 

   

}


Note :


You can configure an event’s propagation so that it propagates to ancestor components that are not direct parents of a child component. 

To do so, you can set the bubbles attribute when creating the event:


const myEvent = new CustomEvent('myevent', { bubbles: true };


You can also stop the event propagation at any time with Event.stopPropagation().


3.Passing data to components that share no common ancestry


Sometimes you need to send data to components that share no common ancestry. 

For example, you may need to send data to or from a component hosted in a different region of a Lightning page or in a utility bar. 

This type of communication can be achieved with the Lightning Message Service or with the pubsub module.


1.Lightning message service

2.pubsub module


Lightning message service :


The Lightning Message Service (LMS) is the preferred solution for communicating between components that aren’t in the same DOM tree.

LMS also allows communication between the three Salesforce UI technologies: Lightning Web Components, Aura and Visualforce.


LMS provides a publish/subscribe mechanism that allows for the exchange of messages between components. 

For the sake of brevity and in order not to duplicate documentation, we won’t dive into the technical details of 

how to publish and subscribe to Lightning messages – but it requires three key steps:


1.Declare a message channel using the LightningMessageChannel metadata type.

2.Publish a message using the publish() function from the @salesforce/messageChannel module.

3.Subscribe to a message using the subscribe() function from the @salesforce/messageChannel module.



pubsub module :


The pubsub module should be used as a last resort alternative in containers that do not support the Lightning Message Service. 

The module provides a publish/subscribe mechanism for exchanging data across a web page. 

It’s a functional solution but is not officially supported or actively maintained.



Summary :


1.Passing data down the component hierarchy with public properties, setters or methods.

2.Passing data up the component hierarchy with events.

3.Passing data to components that share no common ancestry with the Lightning Message Service or the pubsub module.







Tuesday, 1 June 2021

Error handling Custom Lightning web component

 On the backend, the component javascript detects the type of error object it receives. Depending on which process fails, 

the error object will look slightly different. We are involving some logic here to ensure we drill down to the error message 

and details that are relevant.


//lwcErrorHandling.html 


<template>

  <!--banner-->

  <div class="slds-notify slds-notify_alert slds-theme_alert-texture slds-theme_error" role="alert">

    <!--error graphic-->

    <span class="slds-icon_container slds-icon-utility-error slds-m-right_x-small" title="Description of icon when needed">

      <lightning-icon icon-name="utility:error" alternative-text="Error" title="Error" variant="inverse"></lightning-icon>

    </span>

    <!--error message-->

    <h2>{errorMessageToDisplay}</h2>

    <!--close button-->

    <div class="slds-notify__close">

      <button class="slds-button slds-button_icon slds-button_icon-small slds-button_icon-inverse" title="Close" onclick={closeError}>

        <lightning-icon icon-name="utility:close" alternative-text="Close" title="Close" variant="inverse"></lightning-icon>

      </button>

    </div>

  </div>

</template>


//lwcErrorHandling.js


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


export default class LwcErrorHandling extends LightningElement {

    @api error;

    errorMessageToDisplay = '';


    // this runs every time this component is loaded

    connectedCallback(){

        this.errorMessageToDisplay = 'An error occurred \n';

        console.log(this.error);

        

        // getting meaningful error message depending on error type

        // handles errors from wire & regular apex methods

        if(this.error.body){

            if (Array.isArray(this.error.body)) {

                this.errorMessageToDisplay += this.error.body.map(e => e.message).join(', ');

            }

            else if(typeof this.error.body === 'object'){

                let fieldErrors = this.error.body.fieldErrors;

                let pageErrors = this.error.body.pageErrors;

                let duplicateResults = this.error.body.duplicateResults;

                let exceptionError = this.error.body.message;


                if(exceptionError && typeof exceptionError === 'string') {

                    this.errorMessageToDisplay += exceptionError;

                }

                

                if(fieldErrors){

                    for(var fieldName in fieldErrors){

                        let errorList = fieldErrors[fieldName];

                        for(var i=0; i < errorList.length; i++){

                            this.errorMessageToDisplay += errorList[i].statusCode + ' ' + fieldName + ' ' + errorList[i].message + ' ';

                        }

                    }

                }

        

                if(pageErrors && pageErrors.length > 0){

                    for(let i=0; i < pageErrors.length; i++){

                        this.errorMessageToDisplay += pageErrors[i].statusCode + ' '+ pageErrors[i].message;

                    }

                }

        

                if(duplicateResults && duplicateResults.length > 0){

                    this.errorMessageToDisplay += 'duplicate result error';

                }

            }  

        }

        // handles errors from the lightning record edit form

        if(this.error.message){

            this.errorMessageToDisplay += this.error.message;

        }

        if(this.error.detail){

            this.errorMessageToDisplay += this.error.detail;

        }


    }


    // runs when the close button on the error banner is clicked

    closeError() {

        // reset variables

        this.errorMessageToDisplay = '';

        this.error = null;

        // create a custom event for resetting the error state

        const closeErrorEvent = new CustomEvent("errorclosed", {

          detail: this.error

        });

    

        // dispatch the custom event to the parent component, this resets the error and hides this component

        // if the parent component triggers another error, this entire component loads again and runs through the connectedCallback logic

        this.dispatchEvent(closeErrorEvent);

      }

}



//accountinfo.html :



<template>


    <!-- error handling -->

    <template if:true={error}>

        <c-errorhandling error={error} onerrorclosed={handleError}></c-errorhandling>

    </template>


    <lightning-card  title="Account Info" icon-name="standard:account">

        <div class="slds-p-around_small">

            <!-- record edit form-->

            <lightning-record-edit-form record-id={recordId} object-api-name="Account" onerror={handleFormError}>

                    <lightning-input-field field-name='Name'></lightning-input-field>

                <!-- submit button -->

                <lightning-button class="slds-m-top_small button-fixed" variant="brand" type="submit" name="save" label="Save"></lightning-button>

            </lightning-record-edit-form>


            <!-- child component -->

            <c-accountinfochild></c-accountinfochild>

        </div>       

    </lightning-card>

</template>



// accountinfo.js


import { LightningElement, api } from 'lwc';


export default class Accountinfo extends LightningElement {

    @api recordId;

    error;

    

    // handle error from child components

    errorCallback(error, stack){

        this.error = error;

    }

    

    // handle errors from self (submit button press)

    handleFormError(event){

        this.error = event.detail;

    }

    

    // handle errors from self

    handleError(error){

        this.error =  error;   

    }

}



//accountinfochild.html


<template>

    <lightning-button variant="brand" label="Click me" title="Click me" onclick={doSomething} class="slds-m-left_x-small"></lightning-button>

</template>



// accountinfochild.js


import { LightningElement } from 'lwc';


export default class Accountinfochild extends LightningElement {

    doSomething() {

        throw new Error('Whoops!');

   }

}