OOPs! Salesforce Lightning Components Have APIs Too!
Lightning Components are objects in the OOP sense. They contain data, and perform operations on that data, and they even manage the presentation layer. We can treat them like the objects they are when designing component interactions. The Lightning Component Framework includes “magical” ways to enable components to communicate, like events and attribute data binding (as covered in an earlier post). However, the Framework also provides the means for a component to expose a custom interface as a set of plain-old API methods that are accessible from any other component that has a reference to it. This post discusses creating an API interface and how best to utilize an API among your components.
The aura:method tag is our gateway into the land of custom Lightning Component APIs. To help our discussion, we’re going to apply this tag and present an API for a basic user messaging component. To get you started, this component’s API will only have three methods:
show(message) - Present a generic message to the user
error(message) - Called when something has gone wrong
remove() - For when you don’t want the message in the markup any longer
For the purpose of demonstrating the UserMessage component, we’ve placed it within a component that has three buttons as shown below. The buttons are only here to demonstrate the functionality of the UserMessage API. In actual use, the method calls to the UserMessage API would be made from the controller and/or helper methods as needed during the containing component’s management of user interactions (such as when saving a record).
The UserMessage component is within the Demo containing component
Demo Component Controller
As you can see from the code above, very little is required to use and access the component. Once it’s added to the markup, it can be located by its aura:id, and then API methods can be called using the simple dot notation we’re accustomed to. Now it’s time to cover how those API methods are defined in the first place.
User Message Component
As already mentioned, the API interface is defined within the component’s markup using the aura:method tag. Looking at the example code that follows, you’ll notice that it’s the “name” attribute that specifies the name of the API method that may be called. Since this example has controller actions with names that differ from the API methods, the “action” attribute is used to explicitly identify the controller action that corresponds to the API method. If you don’t specify that attribute, Lightning will look for a controller action matching the name of the API method itself. But even when the controller and API names are identical, it’s a good practice to specify the action attribute anyway for clearer and more readily understandable code.
API Method Parameters
The “remove” method is an example of the simplest of method definitions as it doesn’t have any parameters, and that’s specified by having an empty aura:method tag. When an API method contains parameters, as do “show” and “error”, each parameter is defined using an aura:attribute tag. This is the same aura:attribute you’re already familiar with, and it can be used within the aura:method context as well. When there are multiple parameters, the order they’re defined in the markup is their order for the method signature when making a call.
If you check out the documentation for aura:method and aura:attribute, you’ll find additional attributes are available on these tags. For example, defining the access scope (e.g. “public” or “global”), and whether or not a method parameter is required.
You may have been wondering how that <div aura:id="messages" /> tag near the bottom of the component markup is used. In our example, that’s the placeholder for where the user messages will ultimately be displayed. In actuality, it’s the only UI related markup for this entire component! You’ll see more on how that div comes into play a bit later on. For now, take a look at these two screenshots.
Sample standard message rendition
Sample error message rendition
When the “Standard” or “Error” buttons are pressed, a styled message box appears between the header and buttons; right where we placed the UserMessage component. In this example, the markup for the message box was dynamically inserted into the DOM. As shown earlier, when the component is first loaded, it has nothing to display and takes up no real estate on the UI. (We’ll talk more about that further down.) Now for the controller and helper.
The controller is mainly passing off the message to display to the helper. However, it’s also indicating the type of message severity styling to be applied to the message. But where did the message content passed in the method parameter go? As you’re about to see in the helper code, Lightning does some of its magic by automatically adding that parameter to the event’s “arguments” attribute.
As promised, the content passed in the “message” parameter is present and available via event.getParam('arguments').message. If there were additional parameters, they would be accessed by name in a similar fashion. (Dynamic creation of components and the ui:message tag, as shown above, are outside of the scope of this blog post. So please forgive us for not explaining those further.)
Closing the dialog rendition
You may have noticed that the result of closing the message dialog box (by clicking the ‘X’ in the upper right-hand corner) does not collapse the space between it and the buttons. That’s because the DOM elements for the message dialog are still present, they’re just hidden from view. That’s where the “Remove” functionality comes into play. By explicitly removing the DOM elements, the display layout is returned back to its original format (as in the first image above).
A fully baked-out version of this messaging component might allow the caller to specify a title, and control whether the dialog is closable or not. It would also include methods for showing confirmation, information, and warning messages too, but all that is left as an exercise for you.
Providing a custom API via aura:method is designed for when one component has a reference to the component having the API, like an outer component calling one of its inner / contained components. In addition to the messaging component described in this post, other use cases for developing components with an API include things like:
Spinner Modal - with start() and stop() methods to respectively show/hide the spinner
Record List - Adding a new record to the component, containing a (potentially sorted) list of records, by calling its addRecord(recordObject) method
History Tracking - Like a calculator tape or navigation breadcrumbs, such as plus(5) or addPage(‘accounts’)
Status - Rendering task status as an icon, e.g. showAsCompleted()
Exposing a custom API for a Lightning component allows the hiding of potentially complex operations, and invoking those operations without managing events. API methods provide a “fire and forget” paradigm, which is also achievable with events, except without their development overhead. Plus, APIs present a more intuitive interface that’s easier to use and document than describing the particular event(s) that must be fired for the component to handle.
You may not have thought of Lightning Components in an OOP context very much before, but hopefully you’ll consider it now! In addition to providing encapsulation and inheritance, components can provide a rich API interface. A well designed API makes your component easier to understand, facilitating reuse throughout a project. So when it’s appropriate, let aura:method be a part of your Lightning Development arsenal.
If you like geeking out about Lightning,
look for us in our lab coats at Dreamforce.
We'd love to meet you!