Sunday, 26 July 2015

Lightning Components and Custom Apex Classes

Lightning Components and Custom Apex Classes

Overview

This week I’ve been generating summary information in an Apex controller and surfacing this through a Lightning Component. When designing the solution, my initial thoughts were that I’d either:

  • have the component call multiple methods on the controller - not as inefficient as it sounds thanks to ‘boxcarring’, described in detail in Peter Chittum’s blog post.
  • return the results as a JSON string and parse this client side to access the details

However, after looking through the Lightning Components Developer’s Guide, a third way presented itself - the framework allows the Apex controller to return a instance of a custom Apex class, which is then automatically converted into a JavaScript object for use client-side.

Scenario

For the purposes of this blog post I have a simple use-case of returning the total number of Accounts, Contacts and Opportunities in the system. 

Code

The summary information is encapsulated in the RecordCounts custom Apex class, which also doubles as the Apex controller for the component, providing the GetRecordCounts method to retrieve the information. Note that the methods and attributes for use client-side have the AuraEnabled annotation:

public class RecordCounts {
    @AuraEnabled
    public Integer numAccounts {get; set;}
    
    @AuraEnabled
    public Integer numContacts {get; set;}
    
    @AuraEnabled
    public Integer numOpportunities {get; set;}
    
    @AuraEnabled
    public static RecordCounts GetRecordCounts()
    {
        RecordCounts result=new RecordCounts();
        result.numAccounts=[select count() from Account];
        result.numContacts=[select count() from Contact];
        result.numOpportunities=[select count() from Opportunity];
        
        return result;
    }
}

The lightning component is very straightforward - it defines that the Apex controller is ‘RecordCounts’, provides an attribute to store the retrieved record count instance in and has markup to output the value.  The information is retrieved from the server via the doInit event handler, which will be invoked when the component is initialised but before it is rendered. 

<aura:component controller="RecordCounts">
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <aura:attribute type="RecordCounts" name="counts" />
    Number of accounts = {!v.counts.numAccounts}<br/>
    Number of contacts = {!v.counts.numContacts}<br/>
    Number of opportunities = {!v.counts.numOpportunities}<br/>
</aura:component>

Note that the type of the ‘counts’  attribute is defined as the name of the custom apex class - RecordCounts. Note also that I can simply access properties from the Apex class using the JavaScript object dot notation, as the record instance has been converted to a Javascript object representation.

In accordance with Lightning Components best practice, the component controller simply delegates to a helper for the init event callback handler:

({
	doInit : function(component, event, helper) {
		helper.doInit(component, event);
	}
})

while the helper executes the server side method and sets the Javascript object representation of the Apex class instance into the ‘counts’ attribute upon success without any intervention from me to process the result or translate it to something that the component can use directly, as this is all handled by the framework:

({
	doInit : function(cmp, ev) {
        var action = cmp.get("c.GetRecordCounts");

        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                cmp.set('v.counts', response.getReturnValue());
            }
            else if (state === "ERROR") {
                alert('Error : ' + JSON.stringify(errors));
            }
        });
        $A.enqueueAction(action);
    }
})

Adding this component to a Lightning application and executing it generates the following output:

Screen Shot 2015 07 26 at 14 19 21

Related Posts

 

6 comments:

  1. How to Block already selected Dates in Lightning Components?

    ReplyDelete
  2. gr8 blog... thanks very helpful for beginners

    ReplyDelete
  3. Simple but useful. Thanks!

    ReplyDelete
  4. Hi Bob,

    Can we instantiate wrapper class instance here?

    ReplyDelete
  5. How would you go about setting a specific property within the wrapperClass outside of the init? Ive attempted something similar to this below, but its returning an error that it can't find "numContacts". Thoughts?

    component.set('v.counts.numContacts',55);

    ReplyDelete
  6. How would you go about setting a specific property within the wrapperClass outside of the init? Ive attempted something similar to this below, but its returning an error that it can't find "numContacts". Thoughts?

    component.set('v.counts.numContacts',55);

    ReplyDelete