Salesforce Lightning Components Standard Controller - An Overview

, salesforcedevs, Developer, development, Force.com, Salesforce, Lightning, Lightning Components

Some Background

One of the things that I have found makes development with Visualforce a lot easier (and in truth makes developing pages on Salesforce easier than other technology stacks) is their standard controller. Without writing a single line of code I can have support for retrieving a saving record(s) straight out of the box.

Currently within the Lightning Component Framework there is no similar structure - and I include the <force:recordView> and <force:recordEdit> components, both of which provide a nice way of displaying data but require you to write the code for saving and if you don’t have the record Id or want a list of records, retrieving. This adds an extra burden to developing Lightning Components which would be a limitation were you trying to learn how to build them coming from another language, platform or just trying to learn from the ground up without an intricate knowledge of Apex.

This is the situation I came across when I was talking to Kerry Townsend (@kerrytownsend) and offered to help her learn how to build Lightning Components for her Dreamforce presentation on the subject (watch this space for some more material to hopefully help others!) Kerry is a fantastic functional consultant who has a great understanding of the declarative side of the platform and has done some programming at university. She is not however a developer and has no deep knowledge of Apex meaning that to learn how to build Lightning Components she would also need to learn how to develop in Apex.

So this is why I have put together this library. It is meant to be easy and lightweight and help someone focus on the JavaScript side of their Lightning Component without worrying that Apex even exists. Is it fully fledged? Probably not. Does it do everything? No. Is it bug free? In my limited testing yes but remember to test yourself. This is a utility to help tide people over if they wish until such time as Salesforce provides a standard controller like set of functionality for Lightning Components.

What is it?

The “library” is 3 classes in 2 class files and a couple of custom labels for error handling. Our classes are:

The LightningStandardController offers a set of utility methods for you to call from your Lightning component to aid in the saving and retrieval of records from Salesforce:

  • Save (both a single record or a list of records)
  • Query (with a query string, an object name and some fields or an object name, fields and parameters)

Just Show Me Some Code!

Firstly, we are going to create a very a simple component that displays the name and site of an account (in the case of retrieving many we simply display the first):

<aura:component controller="LightningStandardController">
    <aura:attribute name="account" type="Account" default="{ 'sobjectType': 'Account'}"/>
    <force:outputField aura:id="accountName" value="{!v.account.Name}"/><br/>
    <force:outputField aura:id="accountSite" value="{!v.account.Site}"/>
    <ui:inputText aura:id="name" label="Enter Search Name:" placeholder="Account Name" />
    <ui:button aura:id="button" buttonTitle="Search" class="button" label="Search" press="{!c.search}"/>
</aura:component>

Firstly we have set the controller attribute of the component to be our LightningStandardController. That is all we need to do to get it connected. The <aura:attribute> we define is for the account we are going to display and two <force:outputField> components we bind to the Name and Site fields on the Account object. For our demo here we add a <ui:inputText> field which is going to be for searching by Account Name. Finally there is a button which is going to call the search method on our component controller, speaking of which:

({
    search : function(cmp, evt) {

        //Retrieve our name parameter from the search input area
        var searchName = cmp.find("name").get("v.value");
        //Create our action referencing the query method on the LightningStandardController
        var action = cmp.get("c.query");
        
        //If we have a search name then lets create our filter object
        var filter;
        if(searchName !== '' && typeof searchName !== "undefined") {
			filter = { "Name" : searchName };
        } 
        
        //Set our parameters for the query method on the LightningStandardController
        action.setParams({ objectType : "Account", fields: ["Name", "Site"], and_filters : filter });
        
        //Set a callback function to populate the account attribute if we get a successful result
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
				cmp.set("v.account", response.getReturnValue()[0]);
            } else if (state === "ERROR") {
                var errors = response.getError();
                if (errors) {
                    if (errors[0] && errors[0].message) {
                        console.log("Error message: " + errors[0].message);
                    }
                } else {
                    console.log("Unknown error");
                }
            }
        });

        //Queue the action to run
        $A.enqueueAction(action);
    }
})

That’s it really. Save, saveMany and runQuery are all called in a similar manner.

Interesting Asides

Firstly, as I was experimenting with I originally intended to use a custom Apex class for passing in the filter parameters (you can see this in an earlier commit on Github). However, there is a current issue with the Lightning framework whereby passing in a parameter of a custom Apex type throws an internal server error (See here) so this original plan had to be skipped.

Another update that was made was to remove the use of overloaded AuraEnabled methods, as it seems that the method with the largest number of parameters is selected and null values are passed in for missing parameters. As such, tweaks were made to ensure that we had a single query method to use for all queries where we are not passing in a pre-defined query string.

Closing

Hopefully Salesforce will fix the issue I highlighted in the asides and more importantly will provide standard controller functionality natively that makes this unrequired.

Share on Twitter, Facebook, Google+
Prev Next