Cacheable apex method [Winter-19]

You can mark an Apex method as storable (cacheable) instead of using setStorable() on every JavaScript action that calls the Apex method to centralize your caching notation for a method in the Apex class.

This change applies to orgs with Lightning components in Lightning Experience, Salesforce Classic, and all versions of the Salesforce app.

Marking a method as storable improves your component’s performance by quickly showing cached data from client-side storage without waiting for a server trip. If the cached data is stale, the framework retrieves the latest data from the server. Caching is especially beneficial for users on high-latency, slow, or unreliable connections, such as 3G networks.

Prior to Winter ’19, to cache data returned from an Apex method, you had to call setStorable() in JavaScript code on every action that called the Apex method. Now you can mark the Apex method as storable (cacheable) and get rid of any setStorable() calls in JavaScript code.

To cache data returned from an Apex method for any component with an API version of 44.0 or later, annotate the Apex method with @AuraEnabled(cacheable=true). For example:

@AuraEnabled(cacheable=true)
public static Account getAccount(Id accountId) {
    // your code here
}

To update an existing component to API version 44.0, remove setStorable() calls in JavaScript code. Annotate the Apex method with @AuraEnabled(cacheable=true) instead of @AuraEnabled, or you get an error response for the action.

Loading a Record using LDS

To load record using LDS is by including force:recordData in your component while specifying the recordId, mode and layoutType or fields attribute.

In the force:recordData tag, specify the ID of the record to be loaded, a list of fields, and the attribute to which to assign the loaded record. force:recordData must specify the following.

  • The ID of the record to load
  • Which component attribute to assign the loaded record
  • A list of fields to load

You can explicitly specify a list of fields to load with the fields attribute. For example, fields=”Name,BillingCity,BillingState”.

or, you can specify a layout using the layoutType attribute. All fields on that layout are loaded for the record. Layouts are typically modified by administrators, so layoutType isn’t as flexible as fields when you want to request specific fields. Loading record data using layoutType allows your component to adapt to layout definitions. Valid values for layoutType are FULL and COMPACT.

 








Lightning Data Service(LDS) in Salesforce

Lightning Data Service(LDS) will work as data layer in Lightning. It is like Standard Controller in Visualforce page, providing access to data without querying. Use LDS to load, create, edit or delete a record in your component without Apex code. LDS handles sharing rules and field-level security for you.

Without LDS each component make independent server call to perform CRUD operation on a record, even all components are pulling same record data. This independent server calls can also lead to an inconsistencies, lead to situations where a server call refreshes one component leaving other components out of date.

LDS identifies and eliminates requests that invoke the same record data, sending a single shared data request that update all relevant components. Not only does this eliminate inconsistent data between components, it also provide a way to cache the data to work offline in case the user get disconnected and sync the data once connection is restored

So LDS provides reusable Aura components that –

  1. Minimize XMLHttpRequests(XHRs)
  2. Fetch record once, reduce network transfer, app server load and database server load.
  3. Cache record data on the client, separate from component metadata.
  4. Shared record data across components.
  5. Enable progressive record loading, caching and merging more fields and layouts into the cache.
  6. Enable proactive Cache population.
  7. Promote consistency by using only one instance of the record data across multiple components.
  8. Create notification when record data changes.

force:recordData

To use LDS , you have to include force:recordData in your component.

To load record in client side, you have to add force:recordData tag to your component and set your recordId, mode and layout or fields attributes.

  • recordId – specifies the record to load. Record can’t be loaded without a recordId.
  • mode – can be set to either EDIT or VIEW which determines the behaviour of notifications and what operations are available to perform with the record.
  • layout – specifies the layout(FULL or COMPACT) used to display the record, which determines what fields are included. Using layoutType allows your component to adapt to layout definitions.
  • fields – specifies which fields in the record to query.

The fields or layoutType attribute must be provided to load a record’s field data. Since admins usually modify layouts, using fields is a more flexible way to get the fields you need.

The force:recordData tag also supports a set of target* attributes, which are attributes that force:recordData populates itself. The target* attributes can be used to allow access from the UI.

  • targetRecord is populated with the loaded record
  • targetFields is populated with the simplified view of the loaded record
  • targetError is populated with any errors

< force:recordData aura:id="forceRecordCmp"
< !-- aura:id is required to reference the component in your Javascript controller -- >
recordId="{!v.recordId}"
layoutType="{!v.layout}"
fields="{!v.fieldsToQuery}"
mode="VIEW"
targetRecord="{!v.record}"
targetFields="{!v.simpleRecord}"
targetError="{!v.error}"
/ >

Aura.Action Vs aura:registerEvent in Lightning

Instead of an Aura.Action attribute, you could use  to register an onclick event in the child component. You’d have to define the event and create an action in the child’s controller to fire the event. This event-based approach requires a few extra steps but it’s more in line with standard practices for communicating between components.

Action has some known limitations:

  • It is discouraged to use component.set() with the Aura.Action attribute types.
  • It is discouraged to use $A.enqueueAction() in the child component to enqueue the action passed to the Aura.Action attribute.

If you want to build some more dynamic, or to overcome these limitations, the recommended way would be to fire an event from the child component that is handled by the parent component to perform the required action using aura:registerEvent

AuraActionEvent.evt

< aura:event type="COMPONENT" description="Event to Execute Aura.Action" / >
AuraActionChild.cmp
<aura:component  >
    <aura:registerEvent name="customEvent" type="c:AuraActionEvent" />

    <lightning:button label="Aura Action Event" onclick="{!c.fireAuraAction}"/>
</aura:component>

AuraActionChildController.js


({
    fireAuraAction : function(component, event, helper) {
        var compEvent = component.getEvent("customEvent");
        compEvent.fire();
    }
})

AuraActionParent.cmp


<aura:component >
<aura:handler name="customEvent" event="c:AuraActionEvent" action="{!c.handleComponentEvent}"/>

<c:AuraActionChild aura:id="auraActionButton" />
</aura:component>

AuraActionParentController.js


({
    handleComponentEvent : function(component, event, helper).  {
        var buttonClicked = event.getSource().getLocalId();
        if(buttonClicked == 'auraActionButton')
            alert('Aura Action using Event Concept');
        }
})

As you can see in the example, in this way you will need to write some extra code, however, we have a finer degree of control, as we could for example add other event handlers dynamically or pass more information to the parent using event attributes. Also,  we are more inline with standard practices for components communication.

Aura.Action attributes in Lightning


<apex:component >
    <aura:attribute name="onClick" type="Aura.Action" >
</apex:component >

An Aura.Action is a reference to an action in the framework. If a child component has an Aura.Action attributes, a parent component can pass in an action handler when it instantiates the child component in its.

Aura.Action is used pass a controller action from a parent component to child component that it contains and is used for on* handlers like onClick.

Limitations for Aura.Action attributes –

Although Aura.Action works for passing an action handler to a child component, its recommend registering an event in the child component and firing the event in the child’s controller instead.Then, handle the event in the parent component.

  • Don’t use cmp.set() in JavaScript code to reset an attribute of  type=”Aura.Action” after it’s previously been set. Doing so generates an error.
  • Don’t use $A.enqueueAction() in the child component to enqueue the action passed to the Aura.Action attribute.

Demonstration –

  1. Create a child component, which contain the Aura.Action attribute type.
  2. Child component also have a on* action handler like onClick.
  3. aura:attribute name should be same as expression inside the onclick action

childAction.cmp –


<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId" access="global" >
    <aura:attribute name="childAction" type="Aura.Action"/>

    <lightning:button label="Execute Aura.Action" onclick="{!v.childAction}"/>
</aura:component >

  1. Embed the child component in Parent and pass the Aura.Action attribute name here to call the ParentComponent controller.
  2. Define the Controller of the parent component.

parentAction.cmp


<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId" access="global">
     <c:Child childAction="{!c.parentAction}"/ >
</aura:component>

parentActionController.js


({
 parentAction : function(component, event, helper) {
    alert('Aura.Action Parent Compoentnt');
}
})

AuraAction.app


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

 Instead of an Aura.Action attribute, you could use <aura:registerEvent> to register an onclick event in the child component. You’d have to define the event and create an action in the child’s controller to fire the event. This event-based approach requires a few extra steps but it’s more in line with standard practices for communicating between components.

 Next1 Click here for using aura:registerEvent over Aura.Action attribute

Apex Controller overview in Lightning

Apex controller with method annotated with @AuraEnabled only will be exposed to use in Lightning component.

public with sharing class SimpleServerSideController {

    //Use @AuraEnabled to enable client- and server-side access to the method
    @AuraEnabled
    public static String serverEcho(String firstName) {
        return ('Hello from the server, ' + firstName);
    }
}

Apex controller must follow these requirements.

  1. Methods must be static and marked public or global. Non-static methods aren’t supported.
  2. If a method returns an object, instance methods that retrieve the value of the object’s instance field must be public.
  3. Use unique names for client-side and server-side actions in a component. A JavaScript function (client-side action) with the same name as an Apex method (server-side action ) can lead to hard-to-debug issues. In debug mode, the framework logs a browser console warning about the clashing client-side and server-side action names.

@AuraEnabled Annotaion – The AuraEnabled annotation enables Lightning components to access Apex methods and properties.

  1. Use @AuraEnabled on Apex class static methods to make them accessible as remote controller actions in your Lightning components.
  2. Use @AuraEnabled on Apex instance methods and properties to make them serializable when an instance of the class is returned as data from a server-side action.

Caching Method Results –

To improve runtime performance, set @AuraEnabled(cacheable=true) to cache the method results on the client. To setcacheable=true, a method must only get data, it can’t mutate data.

Marking a method as storable (cacheable) improves your component’s performance by quickly showing cached data from client-side storage without waiting for a server trip. If the cached data is stale, the framework retrieves the latest data from the server. Caching is especially beneficial for users on high latency, slow, or unreliable connections such as 3G networks.

To cache data returned from an Apex method for any component with an API version of 44.0 or higher, you must annotate the Apex method  with  @AuraEnabled(cacheable=true). For example:

@AuraEnabled(cacheable=true)
public static Account getAccount(Id accountId) {
    // your code here
}

Prior to API version 44.0, to cache data returned from an Apex method, you had to call setStorable() in JavaScript code on every action that called the Apex method. For API version of 44.0 or higher, you must mark the Apex method as storable (cacheable) and you can get rid of any setStorable() calls in JavaScript code. The Apex annotation approach is better because it centralizes your caching notation for a method in the Apex class.

Returning Data from Server side Controller  Next1

Attributes in Lightning

Attributes are the most commonly used element to pass data down the component hierarchy as they are simple to use. In order to pass data down from a parent component to its child, simply use the following code:

Parent Component –

<aura:component>
   <aura:attribute name="parentAttribute" type="String"/>
   <c:childComponent childAttribute="{!v.parentAttribute}"/>
</aura:component>

Child Component –

<aura:component>
   <aura:attribute name="childAttribute" type="String"/>
</aura:component>

In this example, the parent component value of parentAttribute is transferred to the childAttribute of the child component via the  {!v.parentAttribute}  expression.

This is perfect if you just want to display the data in a child component. What about if you also want to execute some logic when the attribute’s value changes?

Consider the following updated definition of childComponent :

<aura:component>
   <aura:attribute name="childAttribute" type="String"/> 
   <aura:handler name="change" value="{!v.childAttribute}" action="{!c.onChildAttributeChange}"/>
</aura:component>

With the addition of a change handler, the child component can now trigger the  onChildAttributeChangecontroller function automatically when the value of  childAttribute changes. This allows us to implement some custom logic such as:

({
    onChildAttributeChange : function (component, event, helper) {
        console.log("Old value: " + event.getParam("oldValue"));
        console.log("Current value: " + event.getParam("value"));
    }
})

We now have established a top-down communication chain between the parent and the child component. This can be summarized in these few steps:

  1. parentAttribute value changes
  2. parentAttribute value is transferred to childAttribute
  3. childComponent’s change handler triggers the onChildAttributeChange controller function

This approach works great for processing an attribute. What about multiple attribute changes? If you want to change two or more attributes and then trigger some logic, this method becomes unwieldy. You can either combine the attributes into a larger object (not always practical) or write a complex synchronization algorithm (please don’t). Instead, I recommend methods for multiple attribute changes

This is article from Salesforce developer blog.