Lightning architecture

In this section, we will discuss key layers of the Lightning architecture that will allow you to have a better framework of understanding as you go deeper.

A key aspect that took me by surprise at first is the need to write client-side controllers in JavaScript. This can be particularly puzzling at first if you are Visualforce developer, but is vital part of being a Lightning developer and is a reflection of its client side architecture. As we saw in the previous chapter, Apex server side controllers still play a part but are mainly for accessing your backend Apex Services and Selectors.

In general, Lightning development is much more componentized. In terms of how the UI is designed and how the code is factored, the two are much more aligned, making it easier to maintain and navigate code. This also gives a much greater emphasis on separation of concerns within the UI tier.

Containers

As we saw in the previous section, we created a basic container called myapp using a standalone Lightning app. It contained a single instance of our mycomponent component. It may not have looked like much but <aura:application> provided a number of services for its components and you as the developer.

  • It constructed the page <HTML> tag and loaded appropriate JavaScript, CSS resources, such as SLDS and the Lightning JavaScript runtime that allows your components to react to user interactions through client side controller code.

    Note

    The extends attribute allows for inheritance from other <aura:application> based applications. The preceding example extending the platforms force:slds application to inject the CSS for SLDS.

  • It loaded the components within its body, namely the mycomponent component, but also any HTML markup that is present is also injected into the page. Each component started its own life cycle within the container. Much like an object in Apex, it was constructed, initialized, tracked, and can be destroyed.

    Note

    Component management is an important service since it helps avoid a common pitfall when developing rich client applications and that is resource management. Each HTML tag and associated data takes up memory in the browser and throughout the life time of the page can easily climb and cause issues if not properly managed.

  • URL-parameters are mapped automatically to aura:attribute components specified in the body of the aura:application. For example:
    /c/myapp.app?myparam=myvalue
    
    <aura:application extends="force:slds">
      <aura:attribute name="myparam" type="String"/>
      <h2>The value of myparam is '{!v.myparam}'</h2>
    </aura:application>

    Results in the following text being displayed in the browser:

    The value of myparam is 'myvalue'

  • URL centric navigation is an important aspect of the user experience and an expectation when users are bookmarking or sharing links to records or certain pages in your web application. Since the application is designed to be long lived and changing the URL causes the entire page to reload, an alternative is needed.

    Modifying the bookmark portion of a URL does not reload the page. As such, Lightning applications leverage this to add more contexts to links stored by users, as well as using it during the applications own navigation.

    You can see this in action as you navigate through Lightning Experience. The framework provides the aura:locationChange event your client side logic can listen to determine when changes are made.

Here is simple example of the URL convention used: /c/myapp.app#showraceresults-2016

You can read more about the attributes of the aura:application in the Lightning Components Developer Guide. Not all these services may be relevant depending on the container you're using. However, it is good to have a basic understanding of how things work even if you only ever leverage the Salesforce containers.

Introducing the Racing Overview Lightning app

The Racing Overview Lightning standalone app is contained in the sample code for this chapter. It can be accessed through /c/RacingOverview. The following screenshot shows what it looks like and gives a first look at the Lightning Components we will be covering in more detail throughout the rest of this chapter:

Introducing the Racing Overview Lightning app

Tip

The sample record data shown in the preceding screenshot can be injected into your developer org by running the following script in Developer Console or Execute Anonymous in Force.com IDE:

PageReferencesampleData = new PageReference('/resource/sampledata'), 
String sampleDataJSON =sampleData.getContent().toString(); 
String orgNameSpace =SObjectDataLoader.class.toString().removeEnd('SObjectDataLoader').removeEnd('.'), 
SObjectDataLoader.deserialize(sampleDataJSON.replace('ns__', orgNameSpace+'__')); 

Lightning Experience and Salesforce1

Salesforce has created its own standard UI containers for its own products and partner applications through the Lightning Application containers, known as Lightning Experience and Salesforce1 Mobile. Both are served up via the /one/one.app URL:

Lightning Experience and Salesforce1

As we have seen in the previous chapters, Salesforce does not restrict loading of its own components in these containers. They provide various ways in which developers can load components they write in order to integrate and extend the standard user experience in respect of their specific application objects and processes.

Salesforce also allows developers to leverage some components they have built and tested for external developer consumption. For example, the force:recordView is used to display a record. The force:showToast component can be used to display popup notifications. We will look at the various ways in which both of these components and Salesforce containers can be used and extended later.

Components

Page level design is no longer the focus in Lightning; thinking component-first is the focus you should have. This does not dismiss the need for good user experience design however. Rather it involves a closer collaboration between UX designer and developer.

Creating one huge component to serve your needs is not recommended and will not embrace the Salesforce UI customization facilities in the way your users will expect. From a coding perspective it will be hard to maintain and not reusable, as it will likely not fit everyone's need.

A better approach is to work with your UX designer on the mockups and think about how you can break up the UI into reusable or distinct elements. Later in this chapter, I will explain how I approached this thinking when devising the components for the FormulaForce application.

Tip

Having a good knowledge of the extensibility points within the Salesforce UIs is also important when designing your user experience. The standard UI may offer most of the user experience required, leaving the developer to focus on one or two single components that add the remainder.

Separation of concerns

Lightning Components are built with separation of concerns in mind from the ground up. Note the use of a Lightning Bundle and the contents as we know them thus far are split into separate files for, the markup (view) and JavaScript code (controller). They are all grouped under a single subfolder. This is a clever way in which Salesforce wants us to really consider the way we engineer our Lightning code and how components interact.

As with most things in engineering, separation of concerns is not a given by just using the technology alone. Some aspects are enforced for you; other things are subject to guidelines and good component design. If you get it right, you will not only get reusable, robust and enduring UI components within your own application UI, but also within the evolving Salesforce containers, as well as the ever increasing number of mobile devices and even integration with third party websites if needed.

Keeping in mind the tenets of separation of concern are as vital when developing a rich client application as they are when engineering your applications backend business logic.

Encapsulation during development

An important aspect of a component's implementation is encapsulation. Its ability to keep its implementation from impacting the operation of other components on the page is a critical aspect of what makes the container model work—especially since in reality all components occupy the same HTML DOM for the page.

As previously mentioned, Lightning Bundles (also known as Aura Definition Bundles) are used to collect together the source files needed to implement each of the specific aspects the Lightning artifact you are creating. The following screenshot shows Compliance Checker component included in this book as shown with in the Force.com IDE:

Encapsulation during development

Note

Also see Aura Definition Bundle type in the Metadata API Developers Guide (https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_auradefinitionbundle.htm).

The following sections discuss the contents of a Lightning Component bundle.

Component markup (.cmp)

Component markup contains the XHTML markup for the components appearance. Its root element is aura:component. It can include references to valid HTML elements and/or other components, as we have seen in the mycomponent example earlier.

Amongst the markup you can also specify attribute bindings, for dynamic aspects of the component, such as a table or field values. Unlike Visualforce these are not bindings to Apex class properties. Bindings refer to attributes defined via the aura:attribute component (typically at the top of this file) or those provided by the platform.

The framework ensures that when the value of an attribute changes (through JavaScript controller code) any markup that references it via a binding expression is refreshed. This is a very powerful feature and avoids the need for extensive coding around the page DOM. In fact, this is generally discouraged in all but advanced scenarios, such as custom component rendering or use of third-party libraries.

The following is a simple example of an attribute definition and usage. When the controller changes the attribute value, the <b> tag will be automatically refreshed:

<aura:attribute name="myattr" type="String"/>

<b>The value of myattr is '{!v.myattr}'</b>

Note

The v prefix denotes a value provider. This one provides access to a components attributes or more specifically its view. Other value providers are available that provide similar functionality to that of Visualforce for accessing Custom Fields and Static Resources through $Label and $Resource. Consult the Lightning Components Developer Guide for more information on these.

Component controller (…Controller.js)

The Controller.js is a JavaScript file that contains the client-side controller code for the component. You must have one of these to define dynamic behavior in your component, including any dynamic initialization. The only way to call code in an Apex controller is from the client side controller code; unlike Visualforce there is no direct way to do so from the markup.

Functions defined relate to corresponding action bindings or aura:handler references in the .cmp file. Actions are events that occur in the browser, such as clicking a button, hovering over an element, scrolling or an event from the container or another component. We will discuss Events in a later section.

Though not enforced, it is recommended that it contains only functions that relate to actions referenced in the .cmp file. More extensive controller code and utility functions should be placed in the Helper.js file described as following. Another motivation for this separation of concerns is that the framework replicates the controller per instance of your component; however there is only ever one instance of the helper.

The following is a simple button markup in .cmp file using the c value provider in an expression to reference a client side controller function:

<lightning:button label="Add Drivers"onclick="{!c.onAddDrivers}"/>

The framework automatically handles the setup of the HTML event listeners for you and routing them to the specified controller method. The component, event and helper parameters are always injected by the framework:

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

Note

The c value provider (controller provider) can also be used within JavaScript to obtain a reference to an Apex Controller method the client code wishes to call. We will review an example of this scenario later in the chapter.

Component Helper (…Helper.js)

A JavaScript file that defines functions are used by the Controller.js and Renderer.js (described as following) files. The framework creates a single instance of these methods which is shared between all component instances. Thus it is recommended you do not store any state and instead leverage the component attributes instead.

This example shows an action binding as referenced by an aura:handler specifying a platform event fired during the initialization of a component. In this case it allows the component to load data from the server dynamically:

<aura:handlername="init"value="{!this}"action="{!c.onInit}"/>

The controller function is fired and delegates to the helper class:

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

The helper function makes a server side call out to the Apex Controller, which is specified through controller attribute within the .cmp file? The c value provider is used here again, but this time to access server side controller methods:

getCalendar :function(component, event ) {
  var action = component.get("c.getRaceCalendar");
  action.setCallback(this,function(response) {
      if(response.getState() === 'SUCCESS') {
        component.set("v.calendar", response.getReturnValue());
      }
    });
  $A.enqueueAction(action);        
}

The $A variable used in the preceding code provides access to Lightning JavaScript API.

Component CSS (.css)

When styling your component, you should leverage the designs and CSS provided by the Lightning Design System, as shown in the mycomponent example earlier. This will ensure your UI continues to stay in line with the Salesforce containers it resides in, as well as, any further advancement in respect to supporting new devices and layout types.

Tip

Using Salesforce base components from the lightning namespace, such as lightning:button, lightning:input and lightning:tabSet automatically ensures you are using SLDS.

However, if you do need to define your own styles, do so via custom CSS classes added to the components .css file. The framework will ensure that these will be encapsulated within the component and will not affect other components on the page.

Note

You should not attempt to modify the .style attribute of the element. If you need to control this you may need to implement a Component Render. The framework provides $A.util.addClass and $A.util.removeClass methods to dynamically manipulate the style of your components markup safely.

The THIS identifier in component CSS must be used to scope the CSS to your component. The following example is used in the Race Calendar component to highlight a race when the user clicks on it:

.THIS .selectedRace{
  background-color:token(colorBackgroundHighlight);
}

The corresponding component markup uses a conditional expression to apply the CSS class (in addition to the SLDS styles). The controller method simply updates the value of the .Selected property from the race binding:

<li class="{!'slds-item ' + (race.Selected ? 'selectedRace' : '')}" onclick="{!c.onRaceClicked}">

Tip

Tokens are a feature of the Lightning framework that allows you to reuse colors and font values expressed by Salesforce in your own styles. The preceding example reuses a token from SLDS that defines what color a selected item is. To include the standard SLDS tokens for use in your components you must create an aura:tokens Lightning Bundle, called defaultTokens. This has already been included in the sample code for this chapter. In this you can also define your own tokens via the aura:token element.

Component Render (…Renderer.js)

In most cases utilizing the component markup, attributes and bindings to manipulate the appearance of the component is the intended way in which to develop your components. You are also discouraged from manipulating the DOM within your helper or controller methods, as the framework will overwrite the changes when it responds to attribute changes. However, in some cases, for example when using a third party JavaScript library you may wish to take control of the DOM directly. In these cases, utilize a component render. Consult the Lightning Components Developer Guide for more information on this facility.

Component Design (.design) and Component SVG (.svg)

These XML based files allow you to customize the appearance of your component when exposing it through the Lightning App Builder and Lightning Community Builder tools, such as configuring the icon used to identify it in the sidebar, allowing your users to use these drag and drop tools to configure Salesforce UIs with the introduction of your packaged components. See Making components customizable later in this chapter for further discussion and examples of this capability.

Component Documentation (.auradoc)

Lightning provides its own documentation framework that is built dynamically based on the components in the org, including those from Salesforce. If you plan to allow other developers to use your packaged components, you can use this file to place documentation that describes the purpose and features of the component.

Tip

You should also leverage the description attribute available on aura:component, aura:attribute, aura:method, aura:event, aura:interface and aura:registerEvent.

Developers can access documentation expressed this way via the URL, https://<myDomain>.lightning.force.com/auradocs/reference.app. See Making components customizable later in this chapter for an example and more discussion on how to expose your components for use outside your package.

Enforcing encapsulation and security at runtime

JavaScript code on a page can traverse the entire page content via the HTML DOM API and obtain information or modify other aspects of the page. This breaks encapsulation at runtime and also breaks security best practices for container architectures such as Lightning. Imagine as an admin you installed a component that you placed on your Home page and it obtained important data and transmitted it back to another server.

While it is unlikely such a component would pass through the Salesforce Security Review and onto AppExchange. There is another reason why in Lightning this type of component is not permitted. Lightning Locker Service, a service designed to physically block this type of logic from executing at runtime, either intentionally or unintentionally has been created by Salesforce. You may unintentionally write code that is considered not secure, by using features that do not comply with the industry standard Content Security Policy (CSP). Features like use of eval and access to the window object are also not supported within the security context the Locker Service creates.

Tip

Locker Service may be activated by default in your org or your customers org. We are thus strongly encouraged to develop and test our code with it enabled if it is not already switch on for your develop and test orgs. There is also a command line utility, Salesforce Lightning CLI, that scans your code for security vulnerabilities. This is well worth investigating and if you have a Continuous Integration process integrating it.

Expressing behavior

Now that we know how Lightning allows us to encapsulate our implementation. It is important to keep in mind the vision behind components is sharing and reusability, not just within your own application, but by other consumers of your application. As with an Apex class exposing an API, it is important to carefully manage what ways consumers of your components are permitted to interact with them.

Access Control

Apex uses the visibility keywords to control what classes, properties and methods are visible, within the scope of the class, within a package and outside of it.

The same level of control is available for the Lightning artifacts you define, such as aura:application, aura:component, aura:attribute, aura:method, aura:event and aura:interface. The default access level in all cases is public, which can be increased to global. For attributes, you can also use private.

Tip

As with Apex, it is actually best practice to mark something as the lowest level of access unless you have good reason to increase it. Thus the samples in this book mostly utilize private attributes, as these represent the internal state of the component and should not be accessible even to any other components, including those within the package. As with general Apex coding, this best practice helps manage coupling and allows for greater factoring freedom.

JavaScript functions within the controller, helper and renderer files are private. You can however use aura:method in your component markup to expose controller functions. The next section goes into more details on the use of methods, events and interfaces.

Tip

As with Apex classes, consider carefully the implications on your components evolution between package releases when specifying the global access control. To support backwards compatibility between upgrades, changes are limited to artifacts that have this access control applied.

Methods, events and interfaces

In Lightning, the method and interface concepts are similar to equivalent concepts in Apex, but apply to components defined in the client. Unlike Apex, interfaces do not express methods, only attributes and events to be implemented by the component.

Note

Like Apex and Java, interfaces that have no attributes or events are known as marker interfaces, as we will discover later in this chapter. The platform makes extensive use of marker interfaces, such as the force:hasRecordId, you can apply to your components to let the Salesforce containers known that your components are ready to be used in various contexts.

It can sometimes be difficult to decide when to use a method in place of an event or vice versa, both provide a means for communicating between components:

  • An event can be quite an overused term in Lightning; it can refer to something sent from an HTML element in the browser or something that occurs during the component's lifecycle, such as the init event. These are known as browser and system level events respectively.
  • As a component author you can also define your own component events and application events. Component events can be fired and handled within the component and by its child components only, whereas application events follow the publish and subscribe model, allowing a component to broadcast to any component on the page an event that wants to listen (subscribe) to the event. Refer to developer's guide for more information relating to event handling when considering owner components versus container (https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/events_application_handling_phases.htm).
  • Methods while easier to implement, tend to create tighter coupling between components, so should be used sparingly, for example to optimize the setup or configuration of child components.

Platform namespaces

Lightning leverages namespaces to segregate layers and functionality. Namespaces are used in the same way as other parts of the platform with a prefix ahead of the artifact you wish to reference, such as a component or interface. The following table lists some of the core namespaces provided with the platform.

Namespace

Purpose

aura

Based on the core framework used to build Lightning, Aura. This remains an open source framework managed by Salesforce. Core components and markup is defined in this namespace. Aspects of this namespace are designed to be agnostic of the hosting platform. You can run Aura on a Java stack if you wanted to!

force

Contains aspects that relate to the Force.com platform, such as knowledge of SObjects and components that replicate the Custom Object Layout UI in Lightning. The force:inputField and force:ouptutField components mimic those found in Visualforce under the apex namespace. It contains interfaces that are used when integrating into the Lightning Experience and Salesforce1 mobile containers. The sample components in this chapter implement these interfaces.

forceCommunity

Represents interfaces used to integrate components into the Lightning Community container.

ui

Includes reusable UI components for basic form based user experiences. These components predate SLDS and thus are not styled with it by default, though you can apply SLDS styles yourself. In terms of roadmap, Salesforce is focusing on the lightning namespace going forward.

lightning

Also known as the Base Lightning Components, these are discussed in further detail in the following section.

The following screenshot of the Aura Documentation page illustrates a good way to discover all of the supported namespaces and the interfaces, components, and API's within them, including those exposed from packages installed in the org:

Platform namespaces

Base components

The components in the lightning namespace are recommended by Salesforce as they provide functionally rich and styled UI components using SLDS. They have stated that they will continue to receive updates as SLDS evolves. Thus they are recommended to ensure components stay in alignment with the look and feel of the rest of the platform.

At time of writing they have not fully replaced those within the ui namespace. However, Salesforce have stated that they will continue to expand them on each release. Meanwhile continue to check first the lightning namespace before the ui namespace, and check both before building your own.

Data services

Lightning Data Services are at the time of writing in Developer Preview, which means that there is a possibility they will change once fully released for production usage. As described in the previous chapter, these can be used as an alternative to writing an Apex Controller in scenarios where you simply wish to create, read, update or delete a record. You can consider them much like the role of the Standard Controller in Visualforce, but instead they exist in the client tier and are interacted with by code in the client controller.

Tip

Be careful not to allow such client side facilities to allow business logic to leak into the client tier. In all but the simplest cases, you will likely still want to delegate to an Apex Service to perform business logic. Also keep in mind the transactional scope; multiple updates from the client will likely each have their own transaction.

Object-oriented programming

Lightning components are in many ways similar to classes and objects used by traditional object-oriented programming languages like Apex, Java and C#. There are many benefits to leveraging OOP techniques with components.

In respect to inheritance consider the following:

  • We have already seen an example inheritance through the extends attribute on the myapp Lightning Application extended force:slds(which is itself an aura:application) to inject SLDS into the application.
  • The defaultTokens token component used in this chapter's sample code to import the SLDS tokens extended the force:base component (which is itself an instance of aura:tokens).
  • You don't have to leverage only the platform provided base components; you can define your own, marking them extensible via the extensible attribute on the aura:component element.

Interfaces also provide a means for our components to integrate with Salesforce containers. The Race Results component implements the following interfaces so that it can be used on the Lightning Experience Home and Record pages:

<aura:component controller="RaceResultsComponentController"implements="force:hasRecordId,flexipage:availableForAllPageTypes"access="global">

Object-Level and Field-Level security

It is the developer's responsibility to enforce object and field security within Lightning. This can be done with the traditional Apex Describe approaches within Apex Controllers. Enforcement should be done at the server end, otherwise unauthorized data can be transmitted to the client and the user could use browser debug tools to inspect the JSON payloads sent from the server.

It is up to the developer as to how the UI manifests to the user. This might simply result in message indicating the user requires more permission or you may choose to dynamically hide (which should include omitting values from the server response) or disallow edit to certain fields or table rows for example.

You might expect that the ui:inputField and ui:outputField components respect field level security, like their Visualforce counterparts. This is not the case, due to the aforementioned reason; enforcement must happen at the server end.

Note

Lightning Data Services are expected to honor object and Field-Level security.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.181.186