Building Lightning Components
Christophe Coenraets
Developer Evangelist
#TrailheadLive
@ccoenraets
http://developer.salesforce.com/trailhead/projects
What you will do
Build an Account Locator built as a a set
of loosely coupled components
communicating through events
Explore different deployment options:
• Lightning App
• Salesforce1 App
• App Builder Composition
AccountMap
AccountList
AccountLocator
AccountListItem
Step 1:
Setting Up Your Environment
1. Sign up for a Developer Edition Org
2. Enable My Domain
3. Deploy to Users
Challenge
Step 2:
Enabling Geolocation on Accounts
1. Add a geolocation field to the Account object
2. Enter sample data
Challenge
Step 3:
Creating an Aura-Enabled Controller
Visualforce Page-Centric Model
1. Browser requests page
Client Server
4. Browser renders html
2. Server executes Apex code
3. Server returns page (html + data)
Show different data? Back to 1
Show different view? Back to 1
Pros
1. Proven model
2. Productivity. Easy to implement
3. Naturally splits large apps into small, manageable units (pages)
Caveats
1. Limited interactivity
2. Higher latency
Visualforce Page Centric Model
Lightning App-Centric Model
1. Browser requests Component
Client Server
3. Browser builds UI with JavaScript
4. Browser requests data
7. Back to 3
2. Server returns Component Bundle
5. Server executes Apex
6. Server returns data (data only!)
Show different data? Back to 4
Show different view? Back to 3
Pros
• Enables highly interactive/immersive user experiences
• Less page refreshes
• Tightly integrated (no iframe)
• Composable
Caveats
• Higher learning curve compared to vanilla Visualforce pages
• Higher level of complexity. Building an app is generally more complex than building a page
Lightning Components App Centric Model
Creating an Aura-Enabled Apex Controller
public with sharing class AccountController {
@AuraEnabled
public static List<Account> findAll() {
return [SELECT id, name FROM Account];
}
}
* You should add code to enforce CRUD and FLS
1. Create an Aura-enabled Apex controller named
AccountController
2. Add a findAll() method that returns accounts that have location
information
Challenge
Step 4:
Creating the AccountLocator Component
Anatomy of a Lightning Component
<aura:component controller="AccountController">
<div>
<div>AccountMap goes here</div>
<div>AccountList goes here</div>
</div>
</aura:component>
Component Parts: Component
UI Markup
Data binding
Attributes
Component
Component Parts: Style
UI Markup
Data binding
Attributes
ComponentStyle
Encapsulated
CSS
1. In Lightning Applications
2. In the Salesforce1 app
3. In App Builder
Where can I use Lightning Components?
Using a Lightning Component in a Lightning App
1. Create a Lightning App
File > New > Lightning Application
2. Embed the Lightning Component
<aura:application>
<c:AccountLocator/>
</aura:application>
Useful for creating fullscreen apps or for testing components during development
Using a Lightning Component in the Salesforce1 App
1. Implement the force:appHostable interface
<aura:component implements="force:appHostable">
2. Create a Tab
3. Add the Tab to Mobile Navigation
1. Create the AccountLocator component
2. Add AccountLocator to the Salesforce1 App menu
Challenge
Step 5:
Creating the AccountList Component
Attributes
• The data of the component
• Available anywhere in the component
• Examples:
<aura:attribute name="price" type="Number"/>
<aura:attribute name="title" type="String"/>
<aura:attribute name="account" type="Account"/>
<aura:attribute name="accounts" type="Account[]"/>
Data Binding {! }
<aura:attribute name="account" type="Account"/>
<p>{!v.account.Name}</p>
 Initial value of <p> is set to the value of account.Name
 Value of <p> automatically updated when value of account.Name changes
Bidirectional Data Binding
<aura:attribute name="price" value="100" type="Number"/>
<ui:inputNumber label="Principal:" value="{!v.price}"/>
 Initial value of inputNumber is set to value of attribute (100)
 Value of price attribute is updated when user types new value in inputNumber
Component Parts: Controller
UI Markup
Data binding
Attributes
Component
Event
Handlers
ControllerStyle
Encapsulated
CSS
<aura:attribute name="counter" type="Number" default="0"/>
<ui:button label="Click me" press="{!c.handleClick}"/>
<div>{!v.counter}</div>
handleClick: function(component, event) {
var counter = component.get("v.counter");
counter = counter + 1;
component.set("v.counter", counter);
}
ComponentControllerEvent Handler Example
Counter
Event Handler Example
Retrieving Data on Init
<aura:attribute name="accounts" type="Accounts[]"/>
<aura:handler name="init" value="{!this}" action="{!c.doInit}" />
doInit : function(component, event) {
var action = component.get("c.findAll");
action.setCallback(this, function(a) {
component.set("v.accounts", a.getReturnValue());
});
$A.enqueueAction(action);
}
ComponentController
Iterating through a List
<aura:attribute name="accounts" type="Account[]"/>
<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
<ul>
<aura:iteration items="{!v.accounts}" var="account">
<li>{!account.Name}</li>
</aura:iteration>
</ul>
Nested Component
• A component used in another component
• AccountListItem Example:
<aura:component>
<aura:attribute name="account" type="Account"/>
<li>{!v.account.Name}</li>
</aura:component>
Using a Nested Component
<aura:attribute name="accounts" type="Account[]"/>
<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
<ul>
<aura:iteration items="{!v.accounts}" var="account">
<c:AccountListItem account="{!account}"/>
</aura:iteration>
</ul>
1. Create the AccountList component responsible for displaying
the list of accounts
2. Create the AccountListItem component that you nest inside
AccountList to render individual accounts in the list
Challenge
Step 6:
Creating the AccountMap Component
• External JavaScript libraries and CSS style sheets must be loaded as static
resources
• Use the <ltng:require> tag to load them
• Loading is asynchronous
• afterScriptLoaded event is triggered after files have been succesfully loaded
Loading External JavaScript Libraries and CSS Files
Loading External JavaScript Libraries
<ltng:require scripts="/resource/leaflet/leaflet.js"/>
Loading External CSS Style Sheets
<ltng:require styles="/resource/leaflet/leaflet.css" />
Loading JavaScript Libraries and CSS Style Sheets
<ltng:require scripts="/resource/leaflet/leaflet.js"
styles="/resource/leaflet/leaflet.css" />
Using the afterScriptLoaded Event
<ltng:require scripts="/resource/leaflet/leaflet.js"
styles="/resource/leaflet/leaflet.css"
afterScriptsLoaded="{!c.renderMap}" />
1. Load leaflet JS library
2. Load Leaflet CSS
3. Render the map when files are loaded
Challenge
Step 7:
Intercomponent Communication
Intercomponent Communication
Application Event Broker
Event Object
<aura:handler event="c:AccountsLoaded"
action="{!c.accountsLoadedHandler}"/>
<aura:registerEvent name="loaded"
type="c:AccountsLoaded"/>
var event = $A.get("e.c:AccountsLoaded");
event.setParams({"accounts": accounts});
event.fire();
AccountMapAccountList
Creating the AccountsLoaded Event
<aura:event type="APPLICATION">
<aura:attribute name="accounts" Type="Account[]"/>
</aura:event>
1. Create the AccountsLoaded Event
2. Trigger the AccountsLoaded Event in AccountList
3. Handle the AccountsLoaded Event in AccountMap
Challenge
Step 8:
Using Events to Center the Map
Intercomponent Communication
Application Event Broker
Event Object
<aura:handler event="c:AccountSelected"
action="{!c.accountSelectedHandler}"/>
<aura:registerEvent name="select"
type="c:AccountSelected"/>
var event = $A.get("e.c:AccountSelected");
event.setParams({"account": account});
event.fire();
AccountMapAccountList
1. Create the AccountSelected event
2. Trigger the AccountSelected event in AccountList
3. Handle the AccountSelected event in AccountMap and center the map on the
selected account location
Challenge
Step 9:
Interacting with the Salesforce1 App
1. Lightning Components enable you to extend standard features
2. Don't reinvent the wheel
For example, if your component needs an account details view: use the standard one, don't create
your own
3. Navigation between standard features and custom components should be smooth and feel
integrated: users shouldn't notice they are switching between standard and custom features
4. Platform events allow you to integrate your custom components into the standard experience
Salesforce1 Integration
Firing a Platform Event
var event = $A.get("e.force:navigateToSObject");
event.setParams({
"recordId": accountId
});
event.fire();
This event will be handled be the Salesforce1 app which will then navigate to
the account's details view
Component Parts: Helper
UI Markup
Data binding
Attributes
Component
Event
Handlers
Controller
Shared
Logic
HelperStyle
Encapsulated
CSS
When a user clicks a marker on the map, load the default
Salesforce1 details view for the selected account
Challenge
Step 10:
Using Components in App Builder
Using a Lightning Component in App Builder
1. Implement the flexipage:availableForAllPageTypes interface
<aura:component implements="flexipage:availableForAllPageTypes">
2. Create a component description in the Design part
<design:component label="AccountList">
</design:component>
3. Enable App Builder for Lightning Experience (PILOT)
4. Drag the component from the component palette in App Builder
Compose AccountList and AccountMap in App Builder
Challenge
Summary
UI Markup
Data binding
Attributes
Component
Design Descriptor
Event
Handlers
Controller
Shared
Logic
HelperStyle
Custom Rendering
Renderer
Encapsulated
CSS
App Builder
Lightning Components Workshop v2

Lightning Components Workshop v2

  • 1.
    Building Lightning Components ChristopheCoenraets Developer Evangelist #TrailheadLive @ccoenraets
  • 2.
  • 3.
    What you willdo Build an Account Locator built as a a set of loosely coupled components communicating through events Explore different deployment options: • Lightning App • Salesforce1 App • App Builder Composition AccountMap AccountList AccountLocator AccountListItem
  • 4.
    Step 1: Setting UpYour Environment
  • 5.
    1. Sign upfor a Developer Edition Org 2. Enable My Domain 3. Deploy to Users Challenge
  • 6.
  • 7.
    1. Add ageolocation field to the Account object 2. Enter sample data Challenge
  • 8.
    Step 3: Creating anAura-Enabled Controller
  • 9.
    Visualforce Page-Centric Model 1.Browser requests page Client Server 4. Browser renders html 2. Server executes Apex code 3. Server returns page (html + data) Show different data? Back to 1 Show different view? Back to 1
  • 10.
    Pros 1. Proven model 2.Productivity. Easy to implement 3. Naturally splits large apps into small, manageable units (pages) Caveats 1. Limited interactivity 2. Higher latency Visualforce Page Centric Model
  • 11.
    Lightning App-Centric Model 1.Browser requests Component Client Server 3. Browser builds UI with JavaScript 4. Browser requests data 7. Back to 3 2. Server returns Component Bundle 5. Server executes Apex 6. Server returns data (data only!) Show different data? Back to 4 Show different view? Back to 3
  • 12.
    Pros • Enables highlyinteractive/immersive user experiences • Less page refreshes • Tightly integrated (no iframe) • Composable Caveats • Higher learning curve compared to vanilla Visualforce pages • Higher level of complexity. Building an app is generally more complex than building a page Lightning Components App Centric Model
  • 13.
    Creating an Aura-EnabledApex Controller public with sharing class AccountController { @AuraEnabled public static List<Account> findAll() { return [SELECT id, name FROM Account]; } } * You should add code to enforce CRUD and FLS
  • 14.
    1. Create anAura-enabled Apex controller named AccountController 2. Add a findAll() method that returns accounts that have location information Challenge
  • 15.
    Step 4: Creating theAccountLocator Component
  • 16.
    Anatomy of aLightning Component <aura:component controller="AccountController"> <div> <div>AccountMap goes here</div> <div>AccountList goes here</div> </div> </aura:component>
  • 17.
    Component Parts: Component UIMarkup Data binding Attributes Component
  • 18.
    Component Parts: Style UIMarkup Data binding Attributes ComponentStyle Encapsulated CSS
  • 19.
    1. In LightningApplications 2. In the Salesforce1 app 3. In App Builder Where can I use Lightning Components?
  • 20.
    Using a LightningComponent in a Lightning App 1. Create a Lightning App File > New > Lightning Application 2. Embed the Lightning Component <aura:application> <c:AccountLocator/> </aura:application> Useful for creating fullscreen apps or for testing components during development
  • 21.
    Using a LightningComponent in the Salesforce1 App 1. Implement the force:appHostable interface <aura:component implements="force:appHostable"> 2. Create a Tab 3. Add the Tab to Mobile Navigation
  • 22.
    1. Create theAccountLocator component 2. Add AccountLocator to the Salesforce1 App menu Challenge
  • 23.
    Step 5: Creating theAccountList Component
  • 24.
    Attributes • The dataof the component • Available anywhere in the component • Examples: <aura:attribute name="price" type="Number"/> <aura:attribute name="title" type="String"/> <aura:attribute name="account" type="Account"/> <aura:attribute name="accounts" type="Account[]"/>
  • 25.
    Data Binding {!} <aura:attribute name="account" type="Account"/> <p>{!v.account.Name}</p>  Initial value of <p> is set to the value of account.Name  Value of <p> automatically updated when value of account.Name changes
  • 26.
    Bidirectional Data Binding <aura:attributename="price" value="100" type="Number"/> <ui:inputNumber label="Principal:" value="{!v.price}"/>  Initial value of inputNumber is set to value of attribute (100)  Value of price attribute is updated when user types new value in inputNumber
  • 27.
    Component Parts: Controller UIMarkup Data binding Attributes Component Event Handlers ControllerStyle Encapsulated CSS
  • 28.
    <aura:attribute name="counter" type="Number"default="0"/> <ui:button label="Click me" press="{!c.handleClick}"/> <div>{!v.counter}</div> handleClick: function(component, event) { var counter = component.get("v.counter"); counter = counter + 1; component.set("v.counter", counter); } ComponentControllerEvent Handler Example Counter
  • 29.
    Event Handler Example RetrievingData on Init <aura:attribute name="accounts" type="Accounts[]"/> <aura:handler name="init" value="{!this}" action="{!c.doInit}" /> doInit : function(component, event) { var action = component.get("c.findAll"); action.setCallback(this, function(a) { component.set("v.accounts", a.getReturnValue()); }); $A.enqueueAction(action); } ComponentController
  • 30.
    Iterating through aList <aura:attribute name="accounts" type="Account[]"/> <aura:handler name="init" value="{!this}" action="{!c.doInit}"/> <ul> <aura:iteration items="{!v.accounts}" var="account"> <li>{!account.Name}</li> </aura:iteration> </ul>
  • 31.
    Nested Component • Acomponent used in another component • AccountListItem Example: <aura:component> <aura:attribute name="account" type="Account"/> <li>{!v.account.Name}</li> </aura:component>
  • 32.
    Using a NestedComponent <aura:attribute name="accounts" type="Account[]"/> <aura:handler name="init" value="{!this}" action="{!c.doInit}"/> <ul> <aura:iteration items="{!v.accounts}" var="account"> <c:AccountListItem account="{!account}"/> </aura:iteration> </ul>
  • 33.
    1. Create theAccountList component responsible for displaying the list of accounts 2. Create the AccountListItem component that you nest inside AccountList to render individual accounts in the list Challenge
  • 34.
    Step 6: Creating theAccountMap Component
  • 35.
    • External JavaScriptlibraries and CSS style sheets must be loaded as static resources • Use the <ltng:require> tag to load them • Loading is asynchronous • afterScriptLoaded event is triggered after files have been succesfully loaded Loading External JavaScript Libraries and CSS Files
  • 36.
    Loading External JavaScriptLibraries <ltng:require scripts="/resource/leaflet/leaflet.js"/>
  • 37.
    Loading External CSSStyle Sheets <ltng:require styles="/resource/leaflet/leaflet.css" />
  • 38.
    Loading JavaScript Librariesand CSS Style Sheets <ltng:require scripts="/resource/leaflet/leaflet.js" styles="/resource/leaflet/leaflet.css" />
  • 39.
    Using the afterScriptLoadedEvent <ltng:require scripts="/resource/leaflet/leaflet.js" styles="/resource/leaflet/leaflet.css" afterScriptsLoaded="{!c.renderMap}" />
  • 40.
    1. Load leafletJS library 2. Load Leaflet CSS 3. Render the map when files are loaded Challenge
  • 41.
  • 42.
    Intercomponent Communication Application EventBroker Event Object <aura:handler event="c:AccountsLoaded" action="{!c.accountsLoadedHandler}"/> <aura:registerEvent name="loaded" type="c:AccountsLoaded"/> var event = $A.get("e.c:AccountsLoaded"); event.setParams({"accounts": accounts}); event.fire(); AccountMapAccountList
  • 43.
    Creating the AccountsLoadedEvent <aura:event type="APPLICATION"> <aura:attribute name="accounts" Type="Account[]"/> </aura:event>
  • 44.
    1. Create theAccountsLoaded Event 2. Trigger the AccountsLoaded Event in AccountList 3. Handle the AccountsLoaded Event in AccountMap Challenge
  • 45.
    Step 8: Using Eventsto Center the Map
  • 46.
    Intercomponent Communication Application EventBroker Event Object <aura:handler event="c:AccountSelected" action="{!c.accountSelectedHandler}"/> <aura:registerEvent name="select" type="c:AccountSelected"/> var event = $A.get("e.c:AccountSelected"); event.setParams({"account": account}); event.fire(); AccountMapAccountList
  • 47.
    1. Create theAccountSelected event 2. Trigger the AccountSelected event in AccountList 3. Handle the AccountSelected event in AccountMap and center the map on the selected account location Challenge
  • 48.
    Step 9: Interacting withthe Salesforce1 App
  • 49.
    1. Lightning Componentsenable you to extend standard features 2. Don't reinvent the wheel For example, if your component needs an account details view: use the standard one, don't create your own 3. Navigation between standard features and custom components should be smooth and feel integrated: users shouldn't notice they are switching between standard and custom features 4. Platform events allow you to integrate your custom components into the standard experience Salesforce1 Integration
  • 50.
    Firing a PlatformEvent var event = $A.get("e.force:navigateToSObject"); event.setParams({ "recordId": accountId }); event.fire(); This event will be handled be the Salesforce1 app which will then navigate to the account's details view
  • 51.
    Component Parts: Helper UIMarkup Data binding Attributes Component Event Handlers Controller Shared Logic HelperStyle Encapsulated CSS
  • 52.
    When a userclicks a marker on the map, load the default Salesforce1 details view for the selected account Challenge
  • 53.
  • 54.
    Using a LightningComponent in App Builder 1. Implement the flexipage:availableForAllPageTypes interface <aura:component implements="flexipage:availableForAllPageTypes"> 2. Create a component description in the Design part <design:component label="AccountList"> </design:component> 3. Enable App Builder for Lightning Experience (PILOT) 4. Drag the component from the component palette in App Builder
  • 55.
    Compose AccountList andAccountMap in App Builder Challenge
  • 56.
    Summary UI Markup Data binding Attributes Component DesignDescriptor Event Handlers Controller Shared Logic HelperStyle Custom Rendering Renderer Encapsulated CSS App Builder