Lightning, Visualforce and the DOM | Techila
2725
single,single-post,postid-2725,single-format-standard,ajax_updown_fade,page_not_loaded,,qode_grid_1300,footer_responsive_adv,hide_top_bar_on_mobile_header,qode-content-sidebar-responsive,qode-theme-ver-9.4.2,bridge,wpb-js-composer js-comp-ver-4.12,vc_responsive
 

Lightning, Visualforce and the DOM

LIGHTNING, VISUALFORCE AND THE DOM

Lightning, Visualforce and the DOM

INTRODUCTION

Lightning Components entered beta in the Spring 15 release, were the subject of a Salesforce Developer Week and have been generating a huge amount of interest ever since. Developers now face a choice when building a custom Salesforce UI of whether to use Visualforce or Lightning. To my mind they each bring their own pros and cons, but one scenario where Lighting is an obvious choice (with a few caveats) an application where the business logic will reside on the client in JavaScript.

DEMO PAGE

To demonstrate this, I’m building two versions of a simple page to output basic account details in Bootstrap panels:

Bootstrap panels

LIGHTNING IMPLEMENTATION

One distinguishing feature of the lightning implementation is the number of artefacts :

  • Apex Controller to provide access to data
  • Lightning Component Bundle to output the account panels, consisting of:
    • Lightning Component
    • JavaScript controller
    • JavaScript helper
  • Lightning Application to provide an URL-addressable “page” to view the component

The Apex controller has a single method to retrieve the accounts – note how I can re-use the same method across Lightning and Visualforce by applying more than one annotation:

public class AccountsListController
{
    @AuraEnabled
    @RemoteAction
    public static List<Account> GetAccounts()
    {
        return [SELECT id, Name, Industry, CreatedDate
                FROM Account
                ORDER BY createdDate DESC];
    }
 }
The lightning component is a little lengthy, due to the HTML markup to generate the Bootstrap panels, so I’ve made it available at this gist. The interesting aspects are:
<aura:attribute name="accounts" type="Account[]" />
<aura:handler name="init" value="{!this}" action="{!c.doInit}" />

the first line defines the list of accounts that the component will operate on, while the second defines the JavaScript controller action that will be executed when the component is initialised, which will populate the accounts from the database into the attribute.

The markup to output the panels for the accounts utilises an aura:iteration component,which wraps the bootstrap panel HTML and allows merge fields to be used to access account fields:

<aura:iteration items="{!v.accounts}" var="acc">
  <div class="row-fluid">
    <div class="col-xs-12 fullwidth">
      <div class="panel panel-primary">
        <div class="panel-heading">
      <h3 class="panel-title">{!acc.Name}</h3>
        </div>
      ....
</aura:iteration>

for those from a Visualforce background this is a familiar paradigm – a custom tag that binds to the collection, followed by HTML and merge fields to format the collection elements.

The JavaScript controller is very simple, most of the work is done in the helper, in order to allow reuse elsewhere in the bundle in the future:

({
    doInit: function(component, event, helper) {
    // Display accounts
    helper.getAccounts(component);
    }
})
The JavaScript helper doesn’t have a huge amount of code in it either – it creates an action tied to a server side method, defines the callback to be executed when the action completes and queues the action:
({
getAccounts: function(component) {
var action = component.get(“c.GetAccounts”);
var self = this;
action.setCallback(this, function(a) {
component.set(“v.accounts”, a.getReturnValue());
});
$A.enqueueAction(action);
}
})
the most interesting aspect of this code is the line that sets component’s accounts attribute to the result of the action:
component.set("v.accounts", a.getReturnValue());

that’s all I need to do to update the contents of the page – due to the data binding of the aura:iterator, updating the attribute rewrites the DOM with the new markup to display the accounts.

For the sake of completeness, here’s the markup for the Lightning application, which provides a way for the component to be accessed via a URL:

<aura:application >
    <c:AccountsList />
</aura:application>

VISUALFORCE IMPLEMENTATION

To implement the page in Visualforce, I have the following artefacts:

  • Apex Controller (the same one as in the Lightning section, above)
  • Visualforce Page
  • Visualforce Component containing the JavaScript business logic. This could reside in the page, but I find it easier to write JavaScript in a component without the potential distraction or confusion of the HTML markup.

The Visualforce page has a small amount of markup to pull in the bootstrap resources and provide the containing responsive grid:

<apex:page controller="AccountsListController"applyHtmlTag="false"sidebar="false"
           showHeader="false"standardStyleSheets="false">
  <html>
    <head>
      <apex:stylesheet value="{!URLFOR($Resource.Bootstrap_3_3_2, 'bootstrap-3.3.2-dist/css/bootstrap.min.css')}"/>
      <apex:stylesheet value="{!URLFOR($Resource.Bootstrap_3_3_2, 'bootstrap-3.3.2-dist/css/bootstrap-theme.min.css')}"/>
      <apex:includescript value="{!$Resource.JQuery_2_1_3}"/>
      <apex:includeScript value="{!URLFOR($Resource.Bootstrap_3_3_2, 'bootstrap-3.3.2-dist/js/bootstrap.min.js')}"/>
      <c:AccountsListJS />
    </head>
    <body>
      <div class="container-fluid">
        <div class="row-fluid">
            <div class="col-xs-12 col-md-9">
                <div id="accountsPanel">
                </div>
            </div>
        </div>
      </div>
    </body>
  </html>
</apex:page>

CONCLUSION

So does this mean that we can forget about Visualforce when building apps that primarily execute client-side? Not entirely at present, at least in in my opinion.  Bootstrap lends itself well to Lightning, as its only really concerned with the display of data – it doesn’t try to handle requests and routing, and doesn’t make much use of JavaScript to style elements.  Integration with a framework that carries out progressive enhancement, such as jQuery Mobile, would require a fair bit of custom JavaScript to re-apply the progressive enhancement to the updated DOM elements.

“Explore – Techila Global Services, A Salesforce development company”

Author: techila

No Comments

Post A Comment