Tuesday, 31 December 2019

Passing parameters to apex class from LWC with imperative method

Hi ,

I am going to explain how to pass two parameters into an apex class method using imperative method.

Apex Class:
public with sharing class CalculatorController {
    public CalculatorController() {

    }
    @AuraEnabled(cacheable=true)
    public static Integer calculate2Numbers(integer firstNumber,integer secondNumber){
     
        return (firstNumber+secondNumber);
    }
}


HTML File (Template):

<template>
   <lightning-card title="Calculator with apex class" icon-name="custom:custom63">
      <p class="slds-p-horizontal_small">
        <lightning-input label="First Number" name="fNumber" type="number"
value={fNumber} onchange={handledChange}></lightning-input>
        <lightning-input label="Second Number" name="sNumber" type="number"
value={sNumber} onchange={handledChange}></lightning-input>
        <lightning-input label="Result" type="number" value={resultsum}>
</lightning-input> </br>
        <lightning-button label="Submit" onclick={handleClick}>
</lightning-button>
       </p>
    </lightning-card>
</template>



Javascript File:

The below javascript file has example to invoke method from apex class:
Syntax:
import <nameofthemethod> from '@salesforce/apex/<apex class Name>.<methodName>'
import { LightningElement,wire,trackfrom 'lwc';
import calculate2Numbers from '@salesforce/apex/CalculatorController.calculate2Numbers';
export default class Calculatorwithapex extends LightningElement {
    fNumber;
    sNumber;
    @track resultsum;
    handledChange(event){
        if(event.target.name==='fNumber'){
            console.log('handle Change'+event.target.value);
            this.fNumber = event.target.value;
        }
        else if(event.target.name==='sNumber'){
            console.log('handle Change'+event.target.value)
            this.sNumber = event.target.value;    
        }
       
    }
    handleClick(){
        console.log('hi::button invoked'+this.fNumber+'--'+this.sNumber);
        calculate2Numbers({ firstNumber: this.fNumber,secondNumber:this.sNumber })
        .then(result => {
            this.resultsum = result;
            console.log('hi::'+result);
           // this.error = undefined;
        })
        .catch(error => {
            this.resultsum = undefined;
            //this.error = error;
        });
        
    }
   
   
   

}



Meta File (Configuration File):
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>47.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__Tab</target>
    </targets>    
</LightningComponentBundle>

Referece:
https://www.youtube.com/channel/UCipDch4PvPqm0uY4SK7mi1A

Tuesday, 24 December 2019

Defining public properties and communication between parent to child component

Hi,

We are going to see a small example with @api decorator. It will be useful for defining properties and methods public.

To expose a public property, decorate it with @api. Public properties define the API for a component. An owner component that uses the component in its markup can access the component’s public properties. Public properties are reactive. If the value of a reactive property changes, the component rerenders. When a component rerenders, all the expressions used in the template are reevaluated.

To expose a public method, decorate it with @api. Public methods are part of a component’s API. To communicate down the containment hierarchy, owner and parent components can call JavaScript methods on child components.

Let's see small example here which can be ready to accept values from other components:

HTML file:(resultComponent.html)
<template>
    <div>Addition Result:{result}</div>
</template>

JavaScript file:(resultComponent.js)
import { LightningElement,api } from 'lwc';

export default class ResultComponent extends LightningElement {
    @api result;
}

Configuration file:(resultComponent.js-meta.xml)

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


You can pass the values to "result" property with decorator @api from another component. You have to kebab case to include the component and its properties. 
<c-result-component result={result}></c-result-component> 

I am adding this to the calculator example as shown below.

<template>
    <lightning-card>
        <h3 slot="title">
            <lightning-icon icon-name="utility:connected_apps" size="small">
</lightning-icon>
            Calculator Example
        </h3>
        <div slot="footer">
                <!--lightning-badge label={result}></!--lightning-badge-->  
                <c-result-component result={result}></c-result-component> 
        </div>
        <p class="slds-p-horizontal_small">
            <lightning-input value={firstNumber} name="fnumber" 
label="First Number" onchange={handleChanges}></lightning-input>
            <lightning-input value={secondNumber} name="snumber" 
label="Second Number" onchange={handleChanges}></lightning-input>

        </p>
    </lightning-card>
</template>



Reference:
https://developer.salesforce.com/tv/lwc-video-gallery/
https://developer.salesforce.com/docs/component-library/documentation/lwc/js_props_public
https://github.com/trailheadapps/lwc-recipes/blob/master/force-app/main/default/lwc

Tuesday, 17 December 2019

Simple Calculator Example with Lightning Web Components

Hi ,

Here let's talk about a simple example of a Calculator with a track decorator. @track decorator should be where we need to re-render the changes of a property to the template (HTML file) in the Lightning Web component only but not for all properties.
in the following, we are decorating only one property "result" with "track".

Let's see three files how it looks like. Here we are using  <lightning-card> also for UI design.

calculator.html


<template>
    <lightning-card>
        <h3 slot="title">
            <lightning-icon icon-name="utility:connected_apps" size="small"></lightning-icon>
            Calculator Example
        </h3>
        <div slot="footer">
                <lightning-badge label={result}></lightning-badge>                
        </div>
        <p class="slds-p-horizontal_small">
            <lightning-input value={firstNumber} name="fnumber" label="First Number" onchange={handleChanges}></lightning-input>
            <lightning-input value={secondNumber} name="snumber" label="Second Number" onchange={handleChanges}></lightning-input>

        </p>
    </lightning-card>
</template>


calculator.js


import { LightningElement,track } from 'lwc';

export default class CalcTest extends LightningElement {
    firstNumber=0;
    secondNumber=0;
    @track result=0;
    handleChanges(event){
        if(event.target.name==='fnumber'){
            this.firstNumber= event.target.value;
        }
        if(event.target.name==='snumber'){
            this.secondNumber= event.target.value;
        }
        this.result = parseInt(this.firstNumber)+ parseInt(this.secondNumber);
    }
}
calculator.js-meta.xml


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


Output:


References:
https://www.youtube.com/channel/UCipDch4PvPqm0uY4SK7mi1A
https://developer.salesforce.com/tv/lwc-video-gallery/
https://developer.salesforce.com/docs/component-library/documentation/lwc/reference_decorators
https://developer.salesforce.com/docs/component-library/documentation/lwc/lwc.js_props_private_reactive

https://developer.salesforce.com/docs/component-library/documentation/lwc/reference_decorators

Friday, 13 December 2019

Supported Salesforce Experiences and Tools for Lightning Web Components

Hi,

Lightning web components are supported in many Salesforce experiences and tools. To use a Lightning web component with an unsupported experience or tool, wrap it in an Aura component.

These Salesforce experiences and tools are supported.


  • Lightning Experience
  • Salesforce App
  • Lightning Communities
  • Lightning App Builder
  • Community Builder
  • Standalone Apps
  • Lightning Components for Visualforce
  • Lightning Out (beta)
  • Custom Tabs
  • Utility Bars
  • Flows
  • First-Generation Managed Packages
  • Second-Generation Managed Packages
  • Unlocked Packages
  • Unmanaged Packages
  • Change Sets
  • Metadata API—LightningComponentBundle
  • Tooling API—LightningComponentBundle, LightningComponentResource
  • EMP API
  • Embedded Service Chat
  • Gmail and Outlook integration
Unsupported Experiences and Tools

Lightning Web Components doesn’t currently support these Salesforce experiences and tools. To use a Lightning web component with these experiences and tools, wrap the component in an Aura component.

  • Salesforce Console APIs (Navigation Item API, Workspace API, Utility Bar API)
  • URL Addressable Tabs
  • Conversation Toolkit API, Omni Toolkit API, Quick Action API
  • Standard Action Overrides, Custom Actions, Global Actions, List View Actions, Related List View Actions
  • Chatter Extensions

NOTE Salesforce Mobile SDK doesn’t support Lightning Web Components. The workaround of wrapping a Lightning web component in an Aura component is also unsupported.


Reference:

https://developer.salesforce.com/docs/component-library/documentation/lwc/get_started_supported_javascript


Thursday, 12 December 2019

Defining a Property in Lightning Web Component

Hi ,

I am going to explain a simple example about a property and render the value of it on HTML file of lightning web component.

As we know we have three main files required for any lightning web component. Those are
HTML ,Javascript,Meta files.

Lets have a simple Helloworld example:

When you create lightning web component with the name "helloworld" it creates the Lightning Web Component bundle with three basic required files as shown below.


Let's write a simple html markup in
"helloworld.html". Here <template> is root tag always.

<template>
    <lightning-card title="HelloWorld" icon-name="custom:custom14">
        <div class="slds-m-around_medium">
            <p>Hello, {greeting}!</p>
            <lightning-input label="Name" value={greeting} onchange={changeHandler}></lightning-input>
        </div>
    </lightning-card>
</template>

Let's define property "greeting" with @track decorator in java script file "helloworld.js"

import { LightningElementtrack } from 'lwc';
export default class HelloWorld extends LightningElement {
    @track greeting = 'World';
    changeHandler(event) {
        this.greeting = event.target.value;
    }
}

here "@track" decorator makes your property reactive and render the changes on html file

in java script we have one property "greeting" with "@track" decorator and one function "changeHandler" where we set the value to property for any change from "lightning-input".

Now  let's look at meta file (configuration file): helloworld.js-meta.xml

<?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>


In meta file we can maintain the configurations of Lightning Web Components.
The configuration file defines the metadata values for the component, including the design configuration for Lightning App Builder and Community Builder.

Here we have the following things:
<apiVersion> :A double value that binds the component to a Salesforce API Version.

<isExposed> : It can be used to expose our component to App Builder or Community Builder.
If isExposed is false, the component is not exposed to Lightning App Builder or Community Builder.
To allow the component to be used in Lightning App Builder or Community Builder, set isExposed to true and define at least one <target>, which is a type of Lightning page.

<targets>:
Specifies where the component can be added, such as on a type of Lightning Page or in Embedded Service Chat. If you want your component to appear in the Lightning App Builder or in Community Builder, specify at least one Lightning page type.

Here our component exposed to "App page,Record Page,Home Page" of App Builder.

Output:






Whatever we type in input it immediately renders to "greeting" property because "@track" decorator.

Reference:
https://www.youtube.com/channel/UCipDch4PvPqm0uY4SK7mi1A
https://developer.salesforce.com/docs/component-library/documentation/lwc

Wednesday, 11 December 2019

What Lightning Web Component Requires?

Hi,


Lightning Web Components is a new programming model for building Lightning components. 

Every Lightning Web Component requires the following files:

  • HTML File - which has markup and renders UI
  • Javascript File - which has  logic and properties 
  • Meta File - which has component information about where it has to be exposed
  • CSS File (Optional)
  • SVG (Optional)

HTML File:


 Javascript File:

                                          

Meta File
                                     





References:

Sunday, 8 December 2019

Javascript Decorators of Lightning Web Component

Hi ,

Decorators add functionality to property or function. The ability to create decorators is part of ECMAScript, but the following decorators are unique to Lightning Web Components.

  • @track
  • @api
  • @wire

@track

Private properties that contain a primitive value are reactive. If a reactive property is used in a template and its value changes, the component re-renders.

If a private property contains an object, to mark is as reactive, annotate it with @track. LWC tracks changes on the object's properties. If a property is used in a template and its value changes, the component re-renders.


@api



To expose a public property, decorate it with @api. Public properties define the API for a component. To communicate down the component hierarchy, an owner component can access and set a child component’s public properties.
Public properties are reactive. If the value of a reactive property changes, the component’s template renders any content that references the property. For more information, see Public Properties.To expose a public method, decorate it with @api.
Public methods also define the API for a component. To communicate down the component hierarchy, owner and parent components can call JavaScript methods on child components.

@wire

It will be used to read Salesforce data, Lightning web components use a reactive wire service. When the wire service provisions data, the component rerenders. Components use @wire in their JavaScript class to specify a wire adapter or an Apex method.


Referece:


Thursday, 28 November 2019

Prepare email message with Template using renderStoredEmailTemplate method

Hi ,



When we have to use email template then we have to use few methods like "setTemplateId" ,"setWhatId" etc.


But we can use single method "renderStoredEmailTemplate"to  prepare the message from email template. We have to be careful when we use this method because it counts SOQL query.


Eg:

Messaging.SingleEmailMessage message = Messaging.renderStoredEmailTemplate(templateid,whoId,whatId);
message.setsaveAsActivity(false);
Messaging.sendEmail(new List<Messaging.Email>{message});




Reference:
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_email_outbound_messaging.htm

Saturday, 7 September 2019

How to restrict your component to one or more objects?

Hi ,

We can restrict to our component to one or more objects by using the following:

<sfdc:objects> and <sfdc:object>

Here in the following example we are restricting the component to Opportunity which is using the following design component by using  <sfdc:objects> and <sfdc:object>.


<design:component label="Hello World">
    <design:attribute name="subject" label="Subject"/>
    <design:attribute name="greeting" label="Greeting" />    
    <sfdc:objects>       
        <sfdc:object>Opportunity</sfdc:object>
    </sfdc:objects>
</design:component>

If we define the design component with lightning component as above then it will be available for Opportunity Lightning Record page only.

Reference:

Sunday, 18 August 2019

Test Class for Call back class which implements Metadata.DeployCallback interface

Hi,

When we create a class to insert metadata using Metadata class then we write callback class to send notifications or another process about the status of deployment or insert of metadata.

 Callback class:
public class PostInstallCallback implements Metadata.DeployCallback{
public void handleResult(Metadata.DeployResult result,
        Metadata.DeployCallbackContext context) {
       
        if (result.status == Metadata.DeployStatus.Succeeded) {
            // Deployment was successful, take appropriate action.     
           Messaging.SingleEmailMessage  msgObj = new Messaging.SingleEmailMessage ();
            msgObj.setSubject('MetaData insertion succeeded');         
            List<String> emailAddresses = new List<String>{UserInfo.getUserEmail()};
            Metadata.DeployDetails deployDetailsList = result.details;
            List<Metadata.DeployMessage> deploymentMessagesList = deployDetailsList.componentSuccesses;   
            String errorMessageBody = '';
            for(Metadata.DeployMessage messageObj:deploymentMessagesList){
                if(messageObj.success==true && !String.valueOf(messageObj.fullName).split('\\.')[1].containsIgnoreCase('xml')){
                    errorMessageBody+=String.valueOf(messageObj.fullName).split('\\.')[1]+'\n';
                }
            }
            errorMessageBody +=' records created';
            msgObj.setPlainTextBody(errorMessageBody);
            msgObj.setToAddresses(emailAddresses);
            Messaging.sendEmail(new List<Messaging.Email>{msgObj});         
        } else {
            // Deployment wasn’t successful, take appropriate action.
            Messaging.SingleEmailMessage  msgObj = new Messaging.SingleEmailMessage ();
            msgObj.setSubject('MetaData insertion failed');
            msgObj.setPlainTextBody(result.details+'='+result.errorMessage);
            List<String> emailAddresses = new List<String>{UserInfo.getUserEmail()};     
            Metadata.DeployDetails deployDetailsList = result.details;
            List<Metadata.DeployMessage> deploymentMessagesList = deployDetailsList.componentFailures;   
            String errorMessageBody = '';
            for(Metadata.DeployMessage messageObj:deploymentMessagesList){
                if(messageObj.success==false){
                    errorMessageBody+=messageObj.problem+'\n';
                }
            }
            msgObj.setPlainTextBody(errorMessageBody);
            msgObj.setToAddresses(emailAddresses);
            Messaging.sendEmail(new List<Messaging.Email>{msgObj});
        }
    }
}


Test Class:

@isTest
private class PostInstallCallbackTest {
@IsTest
    static void testMyCallback() {
       
        // Instantiate the callback.
        Metadata.DeployCallback callback = new PostInstallCallback();     
        // Create test result and context objects.
        Metadata.DeployResult result = new Metadata.DeployResult();
        result.status = Metadata.DeployStatus.Succeeded;
        Metadata.DeployMessage messageObj = new Metadata.DeployMessage();
        messageObj.changed = true;
        messageObj.success = true;
        messageObj.fullName='';
        messageObj.componentType ='CustomMetadata';
        messageObj.fullName = 'VAT_Rate.SreeVardhan3';
        Metadata.DeployDetails deployDetailsObj = new Metadata.DeployDetails();
        deployDetailsObj.componentSuccesses.add(messageObj);
        result.details = deployDetailsObj;     
        Metadata.DeployCallbackContext context = new Metadata.DeployCallbackContext();
       
        // Invoke the callback's handleResult method.
        callback.handleResult(result, context);
    }
    @IsTest
    static void testMyCallbackErrorMessage() {
       
        // Instantiate the callback.
        Metadata.DeployCallback callback = new PostInstallCallback();     
         // Create test result and context objects.
        Metadata.DeployResult result = new Metadata.DeployResult();
        result.status = Metadata.DeployStatus.Failed;
        Metadata.DeployMessage messageObj = new Metadata.DeployMessage();
        messageObj.changed = false;
        messageObj.success = false;   
        messageObj.componentType ='CustomMetadata';
        messageObj.fullName = 'VAT_Rate.SreeVardhan3';
        messageOBj.problem = 'Default: value not of required type: 1';
        messageObj.problemType = Metadata.DeployProblemType.Error;
        Metadata.DeployDetails deployDetailsObj = new Metadata.DeployDetails();
        deployDetailsObj.componentFailures.add(messageObj);
        result.details = deployDetailsObj;     
        Metadata.DeployCallbackContext context = new Metadata.DeployCallbackContext();       
        // Invoke the callback's handleResult method.
        callback.handleResult(result, context);
    }
}


References:
https://trailhead.salesforce.com/en/content/learn/modules/apex_metadata_api/apex_metadata_api_testing

Monday, 29 July 2019

The SOQL Count() Function Doesn’t Count (As Much) Toward Limits

Hi,

Previously, each individual record matched by the SOQL COUNT() and COUNT(fieldName) functions counted toward the query row limit. So requesting a count could have a significant impact on governor limits, especially when working with many records. Now, if a query using one of these functions returns an integer, it only counts as one query row toward the governor limit. If a query using one of these functions returns an array of AggregateResult objects, only the total number of AggregateResult objects counts toward the limit.

For example, consider the following query.
Integer countOfContacts = [SELECT COUNT() FROM Contact WHERE Account.Name = 'Edge Communications'];
Previously, the number of records matched by this query counted toward the limit. Now this query counts as only one query row toward the limit.
The following query uses the COUNT(fieldName) function. Previously, the number of rows returned counted toward the limit, but now this query counts as a single query row.
AggregateResult ar = [SELECT COUNT(AccountId) rowcount FROM Contact]; // Count contacts with an account only
Integer rowCount = (Integer)ar.get('rowcount');
If a query that uses the COUNT(fieldName) function contains a GROUP BY clause, only the number of resulting AggregateResult objects count toward the limit. For example, in the query in the following example, only one item per aggregated result is counted toward the limit.
List<AggregateResult> res = [SELECT COUNT(id) FROM Contact GROUP BY AccountId];
System.assertEquals(res.size(), Limits.getQueryRows());
Previously, all the records matched by this query counted toward the query row limit.


Reference:

What’s the difference between Einstein Article Recommendations and Suggested Articles?

How Does Einstein Article Recommendations Work? Einstein Article Recommendations helps support agents resolve customer cases efficiently by ...