Saturday, September 29, 2018

Lightning Components Basics : Considerations while calling server-side controller actions

In this blog, we will cover how to call apex class method from Lightning component and different considerations that we need to consider while performing server side call. Actually all calls to server for apex class routed through controller.js function. From lightning component, you can call controller.js function from where you can call apex method.

First of all in order to associate an apex class with lightning component, you have to specify apex class name in controller attribute.

Also remember that all apex methods or apex member variables needs to annotated with @AuraEnabled.

Below is sample apex class which will be called from lightning:

public class SK_LightningBasicsSSController {
    @AuraEnabled
    public static List<Account> findRecentAccounts(){
        return [select id,name,type from Account 
                order by LastmodifiedDate DESC Limit 10];
    }
}

In order to associated this class with lightning component, use below syntax:

<aura:component controller="SK_LightningBasicsSSController">
    <!-- you code-->
</aura:component>

Now we will call apex method on load of lightning component and will display returned list of accounts.

Below is process to call apex method from controller.js

//Create instance of apex method by using c. annotation followed by method name.
var actionName= component.get("c.findRecentAccounts");
//Specify the callback function as all calls are asynchronous. this callback will be invoked once //response is returned by apex class
actionName.setCallback(this, function(response) {
var state = response.getState();
 //Check response state for SUCCESS and ERROR
if (state === "SUCCESS") {
  //store the response in variable
var apexResponse=response.getReturnValue();
console.log('***'+JSON.stringify(apexResponse));
                //set response to attribute value
component.set("v.ltngAccountList",apexResponse);
}else if(state === "ERROR"){
var errors = response.getError();
console.error(errors);
alert('Problem with connection. Contact your system administrator.');
}
});
//do not forget to add below line as this put this request in queue for asynchronous call
$A.enqueueAction(actionName);

Below is complete code snippet:



Important Points to remember:

How to call apex method which contains parameters


If you have method defined with some parameter, for example search string to search account as mentioned below:

@AuraEnabled
Public static List<Account> SearchAccounts(string searchString){
       //your logic
}

So in order to pass parameters to apex class method, create a JSON as mentioned below:
Suppose you have an attribute defined to take input from user say AccName:

<aura:attribute name="AccName" type="string"/>

var actionName= component.get("c.SearchAccounts");
var params = {
                         "searchString" :component.get("v.AccName")
                      };
actionName.setParams(params);

Note:
  • While creating JSON for parameters, key Value should be similar to parameter name in apex method. In our case the apex method parameter name was "searchString" so while creating JSON we specified first key Value as "searchString".
  • If you have multiple parameters, then create JSON as mention below:
          var params ={
                                 "param1":"param value1",
                                 "param2": "param value2",
                                 "param3": "param value3"
                               };

Create helper function which can be reused for different apex method calls

Instead of writing same piece of code to call different apex methods, we can write function in helper.js which can be invoked from controller.js function by passing the parameters to it.

I have created a helper function which takes 4 parameters:
  • Component reference
  • apex class method name
  • callback function name
  • param (to specify parameters if apex method expect some parameters or arguments)
Below is helper function "callToServer"

({
callToServer : function(component, method, callback, params) {
        var action = component.get(method);
        if(params){
            action.setParams(params);
        }
        console.log('****param to controller:'+JSON.stringify(params));
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                callback.call(this,response.getReturnValue());
            }else if(state === "ERROR"){
                var errors = response.getError();
                console.error(errors);
                alert('Problem with connection.'+errors);
            }
        });
        $A.enqueueAction(action);
    }
})

Now if you have to call apex class method from controller.js then use below syntax:

({
    doInit : function(component, event, helper) {
        var params = {
                                 "searchString" :component.get("v.AccName")
                              };
        helper.callToServer(
            component,
            "c.SearchAccounts",
            function(response)
            {
                console.log('apex response :'+JSON.stringify(response));
                component.set("v.ltngAccountList",response);
            }, 
            params
        );
    }
})

How to call different apex methods in sequential order

All calls to apex methods are asynchronous so if there is need to first call a apex method and based on response call another apex method, then you need to make sure that you perform second call to server after getting the response from first function.
So always perform second call to server from inside the callback function which get invoked when asynchronous call finished on server. 

If you use helper function approach to call apex methods then you can use below syntax to call 2 different (searchAccounts and findAccountdetailsapex method in sequential order.

var param1= {
                         "searchString" :component.get("v.AccName")
                     };
helper.callToServer(
component,
"c.SearchAccounts",
function(response)
{
component.set("v.ltngAccountList",response);
var selectedId = response[0].id;
var param2 = {
"ltngAccId": selectedId
}
//creating component dynamically using helper function
helper.callToServer(
component,
"c.findAccountdetails",
function(response)
{
   //your logic
},
param2
);
}, 
param1
);

Use Wrapper to get all data in single call

Avoid multiple calls to server in order to fetch information as it will degrade the performance.
Use wrapper (user defined data types) to return complete information in single server call.


Hope this will help!!!


Friday, September 28, 2018

Lightning Components Basics : Handling Actions in Controller.js

Lightning component bundle comes with different resources like controller.js, helper.js, style.css etc.

All the actions performed on lightning component, can be handled in controller.js.
helper.js worked as an utility which can be called multiple times. If you want to call same piece of code multiple times, then specify it as separate reusable function in helper.js and call it from controller.

I have created a sample lightning component "SK_LightningBasics". Below is code for that:

SK_LightningBasics.cmp

<aura:component >
    <aura:attribute name="ltngFirstname" type="string" default="Sunil"/>
    <aura:attribute name="ltngLastname" type="string" default="Kumar"/>
    <!--Mark up starts-->
    <lightning:input aura:id="userFn" value="{!v.ltngFirstname}" name="ufn" label="Firstname"/>
    <lightning:input aura:id="userLn" value="{!v.ltngLastname}" name="uiln" label="Lastname"/>
    <lightning:input aura:id="useremail" value="" name="uinput" label="Enter Email"/>
    <lightning:button name="btn" label="Display" onclick="{!c.displayMessage}"/>
    <!--Mark up ends-->
</aura:component>

SK_LightningBasicsController.js

({
displayMessage : function(component, event, helper) {
             var fname= component.get("v.ltngFirstname");
             var lname= component.get("v.ltngLastname");
             //how to get input by user 
             //which is not related to attribute
             var emailInputTag= component.find("useremail");
             //Now you can refer any attribute on input tag
            var emailvalue= emailInputTag.get("v.value");
            console.log('*******emailvalue-'+emailvalue);
            //to find label for email input
            var emailLabel= emailInputTag.get("v.label");
            console.log('*******emailLabel-'+emailLabel);
            var alertMsg='displayMessage function get called.\n';
           alertMsg = alertMsg +'Email entered is -'+emailvalue;
           alert(alertMsg);
    }
})

Lightning is based on MVCC (Modal-View-Client side controller-Server side controller), so first functions defined in controller.js is called first and then if needed we can call server side apex class methods.

In above lightning components, we are using onclick attribute on lightning button which invokes controller.js function.

In lightning, we refer controller.js functions using c.annotation inside "{! and }".
For example{!c.displayMessage}

Way to invoke controller.js function when component loaded initially

Lightning framework provide standard events which can be used to invoke controller.js function.
Use below syntax to invoke controller.js function when component is getting loaded:

<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>

Specify the controller.js function which you want to invoke. By using above code snippet, we are calling doInit function in controller.js.

({
doInit: function(component, event, helper) {
             alert(' doInit get called');
      },
      displayMessage : function(component, event, helper) {
             //your logic
      } 
})

Way to invoke controller.js function when any attribute value gets changed

Use change event on attribute to invoke controller.js function.

Sample code snippet:

<aura:attribute name="ltngFn" type="string" default="Sunil"/>
<aura:handler name="change" value="{!v.ltngFn}" action="{!c.OnChangeFunction}"/>

So whenever "ltngFn" attribute value will be changed then, OnChangeFunction will be invoked

({
doInit: function(component, event, helper) {
             alert(' doInit get called');
      },
      displayMessage : function(component, event, helper) {
             //your logic
      },
      OnChangeFunction: function(component, event, helper) {
             alert(' Attribute value gets changed');
      } 
})

In order to test these component code, you can either create lightning tab or create lightning app and preview it. Below is code for lightning app:

SK_LightningBasicsApp.app

<aura:application extends="force:slds">
    <c:SK_LightningBasics/>

</aura:application>

After creating this app, click on preview button on top right side in developer console.

Hope this will help!!


Saturday, September 22, 2018

Lightning Components Basics : Attributes, Expressions and Value Providers

Attributes
Attributes are just like apex class member variables which holds some value and can be used in performing any operation.
Same like apex class member variable, you need to define name of attribute, datatype of attribute and you can also define default value which is optional.
Below is syntax to define attribute:

        <aura:attribute name="firstname" type="string" default="Sunil"/>

Other attributes are:
  • access- Indicates whether the attribute can be used outside of its own namespace. Possible values are public (default), and global, and private.
  • required - If it is required to specify the value of attribute. The default is false.
  • description - Specify the purpose and usuage of attribute.
Supported values for type are Boolean, date, datetime, decimal, double, integer, long, string, collections (list,set,map), standard and custom objects and user defined data types(wrapper class).

Please refer below URL for more information on basic data types:

Component Attributes Types
                                   
Note:
Salesforce recommend using type="Map" instead of type="Object" to avoid some deserialization issues on the server. For example, when an attribute of type="Object" is serialized to the server, everything is converted to a string. Deep expressions, such as v.data.property can throw an exception when they are evaluated as a string on the server. Using type="Map" avoids
these exceptions for deep expressions, and other deserialization issues.

Checking for Types
To determine a variable type, use "typeof" or a standard JavaScript method instead. The "instanceof" operator is unreliable due to the potential presence of multiple windows or frames.

Expression

Expression are kind of formula which can be used within expression delimiters (“{!” and “}”)in expressions, you can specify attributes or different operators to give you output.

          <aura:attribute name="msg" type="String"/>  
            <p>{!'Hello! ' + v.msg}</p>

Value Providers

Value providers helps you to access attributes values and you can use them either in component markup or in JavaScript functions. Using value providers, you can either set or get attributes values.

        <aura:attribute name="msg" type="String"/>  
            <p>{!'Hello! ' + v.msg}</p>

  • Way to find attribute value in controller.js:

               var msgValue = component.get("v.msg")

  • How to set attribute value in controller.js

              component.set("v.msg","Sunil Kumar");

Friday, September 14, 2018

Lightning Component For Timer

I have created a lightning component to display timer. This is useful when you want to display timer to end user so that he/she can understand remaining time.

This component can be used if you are planning to create time tracking app or online exam screen.


Below is complete code snapshot:

Hope this will help!!

Lightning Component for Stopwatch

I have created a lightning component which can work as stopwatch and will display time in "hh:mm:ss" format.



Below is complete code for this lightning component:

Hope this will help!!

Monday, September 3, 2018

lightning:isUrlAddressable Interface: Way to get URL parameters in Lightning Components

In Summer'18 release, Salesforce introduces new interface for lightning components which can be used to fetch URL parameters in lightning components.

Before this, we have to write logic in controller.js function to get current URL and split the url parameters.

If we are using lightning tab and displaying lightning component, then we can fetch URL param by using "{!v.PageReference.state.xxxxx}" where xxxxx is URL parameter name.

I have created a lightning component "SK_URLParamCmp.cmp" in order to explain the usage of this interface. Below is code snapshot:

Now I have created a lightning tab "SK_URLParam_Tab", which will open this lightning component.  Pass any value in URL as "accname" as parameter. Below is sample URL:

"/lightning/n/SK_URLParam_Tab?accname=sunil"

Below is UI snapshot:


Hope this will help!!

Note:

If changes to lightning Components are not reflecting immediately in lightning tabs, then you have to disable the "Enable secure and persistent browser caching to improve performance" option under Caching section in Session settings.

For more details on this setting, please refer below URL:
Improved Performance with Secure Client-Side Caching