How to Call SOAP Callouts In Lightning Components

Let’s discuss here how to use the soap API callouts form the Aura lightning components. Apex can also make callouts to SOAP web services using XML. Here we will be using the simple calculator WSDL from the trailhead. please refer to this link for WSDL 

 

Use WSDL2Apex to Generate Apex Code

Use WSDL2Apex to Generate the apex code from the WSDL.

  1. From Setup, enter Apex Classes in the Quick Find box, then click Apex Classes.
  2. Click Generate from WSDL.
  3. Click Choose File and select the downloaded calculator.xml file.
  4. Click Parse WSDL.

It will generate the apex class as shown below.C lick Generate Apex code. The final page of the wizard shows the generated classes, along with any errors.

 

 

Remote Site Settings 

You need to configure authorize endpoint in the remote site settings. Authorize endpoint URL of the web service callout is https://th-apex-soap-service.herokuapp.com 

 

 

Create An Apex Class

Create an apex class with the below code. This class is calling SOAP callouts.

 

public with sharing class soapcallouts {

@AuraEnabled(cacheable=true)
public static Double getSum(Double val1 ,Double val2 ) {
        calculatorServices.CalculatorImplPort calculator =new calculatorServices.CalculatorImplPort();
        return   calculator.doAdd(val1,val2);
}
@AuraEnabled(cacheable=true)
public static Double getSub(Double val1 ,Double val2 ) {
        calculatorServices.CalculatorImplPort calculator =new calculatorServices.CalculatorImplPort();
        return   calculator.doSubtract(val1,val2);
}
@AuraEnabled(cacheable=true)
public static Double getMul(Double val1 ,Double val2 ) {
        calculatorServices.CalculatorImplPort calculator =new calculatorServices.CalculatorImplPort();
        return   calculator.doMultiply(val1,val2);
}


}

 

Create an Aura Component 

 

create an Aura component with the below code. Here is the .cmp markup

<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId" access="global" controller="soapcallouts">
    <aura:attribute name="inp1" type="Double" default="0" />
    <aura:attribute name="inp2" type="Double" default="0"/>
    <aura:attribute name="res" type="Double" default="0"/>
    
    <lightning:input type="number" name="inp1" label="Enter Input 1" value="{! v.inp1 }"/>
    <lightning:input type="number" name="inp2" label="Enter Input 2" value="{! v.inp2 }"/>
    <lightning:button variant="brand" label="+" title="Sum" onclick="{! c.handleSum }" />
    <lightning:button variant="brand" label="-" title="Sub" onclick="{! c.handleSub }" />
    <lightning:button variant="brand" label="*" title="Mul" onclick="{! c.handleMul }" />
    
    Result - {!v.res}
    
    
</aura:component>

Here is the controller.js code

 

({
    handleSum : function(component, event, helper) {
        var action = component.get("c.getSum");
        action.setParams({ val1 : component.get("v.inp1") ,val2 : component.get("v.inp2")   });
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                component.set("v.res" , response.getReturnValue()) ; 
            }
        });
        $A.enqueueAction(action);
        
    },
    handleSub : function(component, event, helper) {
        var action = component.get("c.getSub");
        action.setParams({ val1 : component.get("v.inp1") ,val2 : component.get("v.inp2")   });
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                component.set("v.res" , response.getReturnValue()) ; 
            }
        });
        $A.enqueueAction(action);
        
    },
    handleMul : function(component, event, helper) {
        var action = component.get("c.getMul");
        action.setParams({ val1 : component.get("v.inp1") ,val2 : component.get("v.inp2")   });
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                component.set("v.res" , response.getReturnValue()) ; 
            }
        });
        $A.enqueueAction(action);
        
        
    }
})

 

Add this component to the page layout and you can able to see the output as shown below

 

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.

 

 

 

Mastering in Lightning component attributes

Introduction

          In this post, I am going to explain lightning component attributes. Component attributes are like member variables on a class in Apex.  Lightning component attributes are used to exchange data between components.  They have typed fields that are set on a specific instance of a component and can be referenced from within the component’s markup using an expression syntax. .Use the <aura:attribute> tag to add an attribute to the component or app. All attributes have a name and a type. Attributes may be marked as required by specifying required=”true”, and may also specify a default value. Let’s look at the following sample where I have defined two attributes of type String, Integer.
<aura:component>
    <aura:attribute name="strAttribute" type="String"/>
    <aura:attribute name="intAttribute" type="Integer" required="true" default="0"/>
    <ui:button aura:id="button" press="{!c.increment}" label="{!v.intAttribute ? v.intAttribute : 0}"/>
</aura:component>
({
    increment : function(c,e,h){
        var prev = c.get("v.intAttribute");
        c.set("v.intAttribute", prev ? prev+1 : 1);
    }
})
From the above example
  1. All attributes have a name and a type. Attributes may be marked as required by specifying required=”true”, and may also specify a default value.

        <aura:attribute name="intAttribute" type="Integer" required="true" default="0"/
    
  2. Must begin with a letter or an underscore
  3. Must contain only alphanumeric or underscore characters
  4. You can set default values
  5. Make it as required
  6. You can access the attributes by using the {!expression}  syntax .for example {!v.intAttribute} allow you to access the intAttribute attribute .

Now, let’s go deep into the different types of attributes and how we will be able to use them in the lightning components.

Basic Attributes Type 

The component supports different types of attributes basic types like Boolean, Integer, String, Number etc and Object type and Complex types like functions and Facets.  Here are the supported basic type values. Some of these types correspond to the wrapper objects for primitives in the apex.

<aura:component>
    <aura:attribute name="typeBoolean" type="Boolean" default="false"/>
    <aura:attribute name="typeDate" type="Date" default="2013-03-06T10:17:36.789Z"/>
    <aura:attribute name="typeDateTime" type="DateTime"  default="123456789" />
    <aura:attribute name="typeDecimal" type="Decimal" default="122.62" />
    <aura:attribute name="typeDouble" type="Double" default="12.1"/>	
    <aura:attribute name="typeLong" type="Long"  default="123"/>
    
    <aura:attribute name="typeMap" type="Map"  default="{ a: 1, b: 2 }"/>
    <aura:attribute name="typeInteger" type="Integer" default="1"/>
    <aura:attribute name="typeString" type="String" default="welcome to salesforce"/>
  
    
    Boolean - {!v.typeBoolean} <br/>
    Date - {!v.typeDate}<br/>
    DateTine - {!v.typeDateTime}<br/>
   
</aura:component>

Once you define the attributes you can able to access by using   {!v.<attribute>} expression syntax as shown below.

<aura:attribute name="number" type="String" default="100000"/>
<ui:inputNumber label="Number" value="{!v.number}"/>

Function Type

 An attribute can have a type corresponding to a JavaScript function. If a child component has an attribute of this type, you can pass a callback from a parent component that contains the child component. You will be able to use function type when you’re returning the asynchronous data from the aura:method callbacks.
<aura:attribute name="callback" type="Function" />

In the below example, The echo aura:method has an aura:attribute with a name of the callback. This attribute enables you to set a callback that’s invoked by the aura:method after execution of the server-side action.

  <aura:method name="echo"
      description="Sample method with server-side call">
        <aura:attribute name="callback" type="Function" />
    </aura:method>
  var params = event.getParam('arguments');
        var callback;
        if (params) {
            callback = params.callback;
        }
'// Check the aura action status 
if action is success then return the callback
  if (callback) callback(response.getReturnValue());

Object Types

An attribute can have a type corresponding to an Object. For example:

<aura:attribute name="data" type="Object" />

Salesforce recommends using type=”Map” instead of type=”Object” to avoid some deserialization issues on the server. You could able to iterate the object as shown below.

 <aura:attribute name="data" type="Object"/>
    <aura:iteration items="{!v.data}" var="item">
        {!item.fieldName} -- {!item.newValue} <br/>
    </aura:iteration>

Collection Types 

An attribute can have a type corresponding to like the set, list or Map. you can use aura:iteration to iterate over the collections.

 <aura:attribute name="typeList" type="List" default="[1,2,3]"/>
    <aura:attribute name="typeStringList" type="String[]" default="['red','green','blue']" />
    <aura:attribute name="typeMapList" type="Map[]"/>
    <aura:attribute name="typeSet" type="Set" default="[1,2,3]"/>
    <aura:attribute  name="typeObject" type="Object" default="['red','green','blue']"/>
	
  Map - {!v.typeMap}<br/>
    Set  - {!v.typeSet[0]}<br/>
    List - {!v.typeList[0]}<br/>
    Object - {!v.typeObject}<br/>

Custom Apex types 

An attribute can have a type corresponding apex wrapper class as an attribute type.

public class ApexClassType {
    @AuraEnabled
    public String message{get;set;}
    @AuraEnabled
    public String warning{get;set;}
    
}

You will be able to refer the apex class as attribute as shown below.

    <aura:attribute name="wrapper" type="ApexClassType"/> 

Facet  Types

A facet is an attribute of type Aura.Component[]. The body attribute is an example of a facet. in this example, I defined two Aura.component[]  attributes which are passed when the component is instantiated. FacetDef component contains the title and footer attributes that are passed when components are instantiated from the FacetWrapper component.

FacetDef.cmp

<aura:component >
    <aura:attribute name="title" type="Aura.component[]" />
    <aura:attribute name="footer" type="Aura.component[]"/>
    <section>
        <div><span></span>{!v.title}</div>
        <div><span> </span>{!v.body}</div>
        <div><span></span>{!v.footer}</div>
    </section>
    
</aura:component>

FacetWrapper.cmp

<aura:component >
    <c:FacetDef aura:id="f1">
        <aura:set attribute="title">
            <ui:outputText value="Salesforce Lightning Component Title "/>
        </aura:set>
        <aura:set attribute="body">
            <ui:outputText value="Salesforce Lightning Component Body"/>
        </aura:set>
        <aura:set attribute="footer">
            <p> Copyright 2017 @{!v.org.Name}  - {!v.org.Street} , {!v.org.City} ,{!v.org.State} ,{!v.org.Country} </p>
        </aura:set>
    </c:FacetDef>
    
</aura:component>

Aura Action Types

An Aura.Action is a reference to an action in the framework. If a child component has an Aura.Action attribute, a parent component can pass in an action handler when it instantiates the child component in its markup. This pattern is a shortcut to pass a controller action from a parent component to a child component that it contains and is used for on*handlers, such as onclick.
AuraAction.cmp
<aura:component>
    <aura:attribute name="pressButton" type="Aura.Action" required="true"/>
    <aura:attribute name="pressDiv" type="Aura.Action" required="true"/>
    
    <ui:button aura:id="theButton" label="Press Me" press="{!v.pressButton}"/>
    <div aura:id="theDiv" onclick="{!v.pressDiv}">Click Me</div> 
</aura:component>

Invoke.cmp

aura:component>
    <aura:attribute name="push" type="Boolean" default="false"/>
    <div aura:id="displayResult">No action has run yet</div>
    <c:AuraAction aura:id="fixture" pressButton="{!c.pressButton}"  pressDiv="{!c.pressDiv}"/>
    
</aura:component>

 

({
    pressDiv: function(cmp, event) {
        var div = cmp.find("displayResult");
        if (div) {
            div.getElement().innerHTML = "Div Action is Presed";
        }
    },
    pressButton: function(cmp, event) {
        var div = cmp.find("displayResult");
        if (div) {
            div.getElement().innerHTML = "Button Action is Pressed";
        }
    },
    
})

Inheritance

A subcomponent that extends a super component inherits the attributes of the super component. Attribute values are identical at any level of extension. There is an exception to this rule for the body attribute, which we’ll look at more closely soon. In this example, I defined an attribute with name parentStr on the parent component. when child component extends the parent component it will inherit the parentStr attribute form the parent component without defining it again same as like apex or java.

Parent.cmp

<aura:component extensible="true">
    <aura:attribute name="parentStr" type="String" default="Parent Component Description" />
    {!v.parentStr}  
</aura:component>

SubCmp.cmp

<aura:component extends="c:Parent">
    <p>sub.cmp description: {!v.description}</p>
</aura:component>

when child component extends the parent component it will inherit the parent component attribute as shown above.

Interface

Other OOP programming like Java, Apex etc lightning component has Object-oriented support to define the interface that defines a set of signatures. the below example contains the set of attributes which you could use when you implement this interface.

<aura:interface >
    <aura:attribute name="instanceId" type="Integer" default="-1"/>
    <aura:attribute name="alias" type="String"    default="panel2"/>
    <aura:attribute name="title" type="String"    default="Default Title"/>
    <aura:attribute name="visible" type="Boolean" default="false"/>
    <aura:attribute name="active" type="Boolean" default="false"/> 
</aura:interface>

when a component implements an interface all attributes, methods, and events will be available by the compiler in the background, so the attributes will be available at runtime – say no need to really ‘implement’  from the interface by yourself as shown below.

<aura:component implements="c:panelType">
    <div class="{!(v.visible ? 'visible' : '') + (v.active ? ' active' : '')}">
        <p>{!v.title}</p>
    </div>
</aura:component>

Custom App Launcher Lightning Component

In this blog, I am going to show how to create a custom app launcher by using Lightning component. The Custom app launcher component will look like a carousel and not as a grid in this example. You can query the details of App launcher by using AppMenuItem SObject . AppMenuItem Represents the organization’s default settings for items in the app menu or App Launcher and its read-only object to view an entry in the Lightning Platform app menu or the App Launcher. You can create a SOQL query to retrieve all items, even items the user does not see from the user interface. There are many ways you can use AppMenuItem. Here are some examples:

  • Build your own App Launcher or app menu in Salesforce. Create a custom page showing all the apps you have access to and that lets you run them using single sign-on.
  • Build your own App Launcher or app menu on a tablet or mobile app. You can have your own app for launching applications on various mobile devices.
  • Build an app launcher into your company’s intranet. There’s no need to have it run on Salesforce because Salesforce APIs let you integrate with Salesforce programmatically and build an app launcher.

Apex Class 

public class AppLauncherinfo {
    @AuraEnabled
    public Static List<AppMenuItem> getAllApps(){
        return [Select Id,Type,ApplicationId,Name,Label,Description,IconUrl,StartUrl,InfoUrl,IsAccessible,IsVisible,LogoUrl,
                SortOrder,MobileDeviceType from AppMenuItem where IsAccessible=true AND Type='TabSet' order by Name ASC];
    }
    
}

Lightning Component 

<aura:component implements="lightning:actionOverride,force:appHostable,force:hasRecordId,force:hasSObjectName,flexipage:availableForRecordHome,flexipage:availableForAllPageTypes"                
                controller="AppLauncherinfo" >
    <aura:attribute type="AppMenuItem[]" name="apps"/>
    <aura:handler  name="init" value="{!this}" action="{!c.doinit}"/>
    <div style="height:600px;">
        <lightning:carousel disableAutoRefresh="false" disableAutoScroll="false" class="slds-carousel__pane">
            <aura:iteration items="{!v.apps}" var="obj">
                <lightning:carouselImage class="slds-carousel__image"
                                         src = "{!obj.LogoUrl}"
                                         header = "{!obj.Label}"
                                         description = "{!obj.Description}"
                                         alternativeText = "{!obj.Name}"
                                         href = "https://www.salesforce.com">
                </lightning:carouselImage>
            </aura:iteration>
        </lightning:carousel>
    </div>
    
    
</aura:component>

 

({
    doinit : function(component, event, helper) {                                                                                        
        var action=  component.get('c.getAllApps');   
        action.setCallback(this,function(response){
            console.log(response.getState());
            if("SUCCESS"===response.getState())
            {
                console.log('response'+response.getReturnValue());
                component.set('v.apps',response.getReturnValue());     
            }
        });
        $A.enqueueAction(action);
        
    }
})

 

After adding this component to the Record page the final app launcher looks like below