Connecting Lightning Components and Visualforce

It’s a busy time. Since January I have been preparing to teach the new ‘Programming Lightning Components‘ course (DEV601) for Salesforce University. It is an excellent in-depth 5 day course. I have taught it twice over the last 5 weeks and am due to teach it again next week. Feedback from attendees has been very positive.

As you interact on these courses you always learn new things, and an interesting add on to Lightning out for Visualforce is worth sharing.

Lightning Out for Visualforce

Lightning Out for Visualforce allows for the embedding of Lightning Components via javascript in a Visualforce page. In order to use it, a visualforce page requires

  • a platform provided javascript library ‘/lightning/lightning.out.js’. There is alternatively a new visualforce tag ‘<apex:includeLightning />’ that can be used.
  • the Lightning Components must be added as an aura dependency to a Lightning Application. Many Lightning Components can be used in this application.
  • The Lightning Application must extend an interface ‘ltng:outApp’.

Currently, the only way to use a Lightning Component in Salesforce Classic (Aloha) is through Lightning Out for Visualforce.

Visualforce Interacting with a Lightning Component

It is possible to call javascript functions in the Lightning Component from Visualforce. The example below uses a built-in callback function provided in the $Lightning.createComponent function to save a reference to the component in the context of the JavaScript in the page.

In the below example, the Visualforce page will display a Lightning Component called ‘lightSabre’ (via a Lightning Application called ‘LightSabreApp’) which as a button that plays a sound. Once the Component is created in the ‘lightSabreDiv’ DOM element, the callback function (which takes a parameter of the component being created) can be used to apply the component reference to a javascript variable in the Visualforce page.

<apex:page >    
    <script src="/lightning/lightning.out.js"></script>
    

<div id="lightSabreDiv"></div>


    <a href="#" onclick="pressButton()">PRESS (to call function within c:LightSabre Controller)</a>

    <script>
        var component;

    	function pressButton() {
            component.helper.playSound(component);
        }
    
        $Lightning.use("c:LightSabreApp", function() {
            $Lightning.createComponent(
                "c:LightSabre",
                {},
                "lightSabreDiv",
                function(cmp) {
                    component = cmp;
                }
            );            
        });
    
    </script>
    
</apex:page>

Lightning Application Markup:

<aura:application access="GLOBAL" extends="ltng:outApp">
    <aura:dependency resource="c:LightSabre" />        
</aura:application>

The page can then call functions within the component. In this case the ‘pressButton()’ javascript function is directly calling a function in the helper of the Lightning Component that plays the sound (in this case a static resource).

Component Markup:

<aura:component description="Linking Visualforce to Lightning">


<div class="centered">
      <ui:button label="Light Sabre!!" press="{!c.playbackBegin}" />
      <audio aura:id="audiofile" src="/resource/lightsaber"></audio>
</div>


</aura:component>

Component Controller:

({
    playbackBegin : function(component, event, helper) { 
        var audioEl = component.find('audiofile').getElement();
        audioEl.play();
    }
})

Component Helper:

({
    playSound : function(component) { 
        var audioEl = component.find('audiofile').getElement();
        audioEl.play();
    },
})

Lightning Out for Visualforce went GA in the Spring 16 release. Lightning Out will also be available for any external site (with authentication) and through the Mobile SDK – these features are in pilot at time of writing and will be available in a future release.

London’s Calling – Feb 5th 2016

I am looking forward to presenting a session at London’s Calling – the first European Salesforce.com event independently organised by the community. The event takes place in London on the 5th February 2016.

The day-long event is a full of amazing sessions and keynotes from Salesforce.com’s Peter Coffee and Erica Kuhl – not to mention the chance to meet and chat with many MVPs from the Developer Community and Developer Evangelists from Salesforce.
London's Calling 2016

My own session is at 10.55am in the ‘Alt’ room (the rooms are called CMD, CTRL, ALT and TAB – love it). The session is a sequel to my session at Dreamforce 15 where I created a complex single page application (SPA) with a Visualforce page and no apex was used. The sequel asks the question – how can I create a similar spa in a Lightning Application with Lightning Components and the Lightning Design System – and what is the experience like?

Visualforce SPA to Lightning SPA

Visualforce SPA to a Lightning SPA

I will post the slide deck for the session here the day before the event – and you might even get free code here too!

Kudos to the team who are organising the event and my thanks for getting the opportunity to speak at it.

My photo - See you all there!

See you all there!

Winter 16: The Curious Incident of the chart with the form tag

Winter 16 has arrived and a fellow lotus-domino-now-a-Salesforce-Developer, Mark Myers (@stickfight) discovered the dead body of a visualforce page, with beautiful C3.js charts, speared by a garden fork an unknown illness.

The Charts stopped working.

The Visualforce page was still displaying, and the area the chart was to be displayed was apportioned correctly – just no chart being generated.

In order to illustrate this, I have created a simple Visualforce Page that displays a chart with c3.js. The following code displayed the chart fine before the Winter 16 rlease – but it does not now.

<apex:page docType="html-5.0" applyBodyTag="false" applyHtmlTag="false" showHeader="false" sidebar="false">
<html>
    <head>
        <!-- Load c3.css -->
        <link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.css" rel="stylesheet" type="text/css" />
        <!-- Load d3.js and c3.js -->
        <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.js"></script>       
    </head>
<body>
<apex:form >
</apex:form>


<div id="chart"></div>


</body>
<script>
var chart = c3.generate({
    bindto: '#chart',
    data: {
      columns: [
        ['data1', 30, 200, 100, 400, 150, 250],
        ['data2', 50, 20, 10, 40, 15, 25]
      ]
    }
});
    </script>    
    </html>
</apex:page>
C3.js not working in Winter 16

C3.js not working in Winter 16

Even more curious – there is no controller here nor is the Javascript doing a lot. And my Project Timesheets app – which uses c3.js – has no issues after the new release.

So, like our 15-year-old blog post hero – Christopher John Francis Boone, I decided to investigate and after stripping out Visualforce mark-up – I found the culprit.

<apex:form>

Removing this tag means the charts get rendered fine.

<apex:page docType="html-5.0" applyBodyTag="false" applyHtmlTag="false" showHeader="false" sidebar="false">
<html>
    <head>
        <!-- Load c3.css -->
        <link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.css" rel="stylesheet" type="text/css" />
        <!-- Load d3.js and c3.js -->
        <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.js"></script>       
    </head>
<body>


<div id="chart"></div>


</body>
<script>
var chart = c3.generate({
    bindto: '#chart',
    data: {
      columns: [
        ['data1', 30, 200, 100, 400, 150, 250],
        ['data2', 50, 20, 10, 40, 15, 25]
      ]
    }
});
    </script>    
    </html>
</apex:page>
C3.js is happy in Visualforce once more

C3.js is happy in Visualforce once more

Sometimes we like to avoid the <apex:form> tag to avoid View State limits and now it seems we, Javascript developers, have a new (unexplained) reason for avoiding it in our Visualforce.

Curious.

Look Ma – No Apex: Mobile Apps with RemoteObjects and Mobile SDK

At Dreamforce 15, I will have the honour of speaking at the Mobile Theatre at 4.30pm on Day One (Tuesday September 15). The topic is mobile development on Salesforce – and creating your first app with the Salesforce Mobile SDK. And no apex is required.

Here is the slide deck for the presentation.

When introducing developers to Apex, one of the key points is that Apex is only used when you need it. Where you can take advantage of the Declarative and built-in features of the platform to fulfill requirements, then thats the optimum solution.

I also try to introduce developers to new development features where possible, and it was while bringing one of my classes through Visualforce Remote Objects that I got the inspiration to make a Mobile SDK app. I also owe James Steer a lot of credit for giving me example code that got me thinking.

The App: Project Timesheets
Blue Wave Technology (who I work for) use Salesforce to manage the business of winning Opportunities, managing project requirements and delivering for customers. The data model used is actually pretty simple; Opportunity records are won from which Project records are created to plan and schedule pieces of work. Blue Wave’s consultants then create Project Timesheet records to indicate work done and time spent on a project.

Project Timesheets Data Model

Project Timesheets Data Model

I wanted to take this model and make a simple but effective app that would allow me to update my project timesheet records quickly. I wanted to create a task-focussed app (ie manage my timesheets) that had our corporate logos and look & feel that had a familiar SPA (Single Page Application) architecture.

I also wanted to show other developers who may not have made mobile apps before how it is created so I stuck to a skill set that I see as common to many developers on the platform:

I also used c3.js to make charts.

The app required the installing and using Salesforce Mobile SDK to create a Hybrid Remote app, a process which doesn’t involve any extra code. Just follow the steps in this Trailhead Module and point to a Visualforce page.

The Visualforce Page:
The entire app is contained in a single Visualforce page. I also use a static resource to bring in AngularJS and a javascript library to handle the tables. We also add extra fields to the Opportunity object and add 2 custom objects – Project__c and Project_Timesheet__c. These can be installed by installing this managed package.

The Visualforce page is quite long – almost 2000 lines – and really the javascript code should be split into separate JS files but it may be easier to follow at first in one page. It is typical for an AngularJS developer to use a structure like angular-seed and tools like bower to manage a project – but I have omitted this here.

The Code: Remote Objects
The page has no controller and relies on AngularJS for its logic, routing and interface. It uses javascript to retrieve, display and manage records in Salesforce using Visualforce Remote Objects.

Remote Objects are proxy objects defined by Visualforce tags and allow for basic querying and DML on the defined objects and fields via javascript. A single tag can contain child tags – one for each sObject in Salesforce. The API name of the sObject and the fields we want to include are defined in the remoteObjectModel tag.

Defining the remoteObjects tag

Defining the remoteObjects tag

To work with a remoteObjectModel in Javascript, define a javascript object and declare it as a new instance of a defined RemoteObjectModel tag in the page. A shorthand local variable can be used here instead of the API name of the Salesforce object.

Defining a JavaScript Object from a RemoteObjectModel

Defining a JavaScript Object from a RemoteObjectModel

The javascript objects can then be used to query for records. Query parameters, ordering, limit and offsets can be used. RemoteObjectModel has a retrieve method that executes queries and returns an error or an array of records in JSON. These can then be pushed into a javascript array for display.

Querying records with RemoteObjectModel

Querying records with RemoteObjectModel

To create a new record or update an existing record the RemoteObjectModel has insert, update, delete and upsert methods. It should be noted that a RemoteObjectModel can include formula fields which cannot be edited, so (as in the below example) a new javascript object should be created and values set within it in order to process the DML event.

Upserting a record with RemoteObjectModel

Upserting a record with RemoteObjectModel

Step-by-Step: Re-create the Project Timesheets Application

Most of the steps here are listed in the Getting Started with Hybrid Development trailhead module.

1. In your developer org install this unmanaged package (https://login.salesforce.com/packaging/installPackage.apexp?p0=04t24000000A459). The metadata is also available on github.

2. Install the Salesforce Mobile SDK along with its pre-requisites (See Installing Mobile SDK for Hybrid Development in link above).
Note: A good way to Install Ant is via homebrew
3. Create a Connected App in your org (see previous link). Ensure to copy out the Consumer Key and the callback URI.
4. Using Terminal or the Command Prompt, navigate to a directory where the application is to be saved
5. Create a Hybrid_Remote app with the command forcedroid create or forceios create.
6. These processes will ask for some settings as follows:

  • Application type: hybrid_remote
  • Application name: ProjectTimesheets
  • Output directory: ProjectTimesheets
  • Package name: com.company.projectTimesheets
  • (forceios only) Organization name: Company Inc
  • Start Page for app: /apex/projectTimesheetsConsole
  • (forceios only) Connected App ID: Paste the consumer key from your connected app
  • (forceios only) Connected App Callback URI: Paste the callback URL from your connected app

6. (forcedroid only) In your project directory, open the www/bootconfig.json file in a UTF-8 compliant text editor and replace the values of the following properties:

  • remoteAccessConsumerKey: Paste the consumer key from your connected app
  • oauthRedirectURI: Paste the callback URL from your connected app

7. Create icons and splash screens to add your branding to the app on the device by adding a graphic to http://ticons.fokkezb.nl/. Use a large graphic and follow the margin and centering recommendations on the site. Replace the folders in your application directory (look for a resources sub-folder) with the folders returned.
8. Run the app by adding it to XCode or Eclipse and running on a real or virtual device.

I am including screenshots of the app here:

My Current Project Timesheets

My Current Project Timesheets

Creating a Timesheet

Creating a Timesheet

Chart of Project Activities (c3.js)

Chart of Project Activities (c3.js)

My Project Timesheets - on iPhone

My Project Timesheets – on iPhone

Here is the slide deck for the presentation.

Speaking at Dreamforce 15

I am speaking at Dreamforce in San Francisco next week. I’m on the Mobile Theatre on Tuesday at 4.30pm (Pacific Time).

I will be showing (and giving away) the code and metadata for a Salesforce Mobile SDK application which should be especially useful for developers who have never created a Mobile SDK app before.

The app is contained in a single Visualforce page with no apex controller required and I only used those frameworks and tools the majority of developers have or can pick up very quickly:

  • Visualforce
  • HTML5
  • CSS3
  • Bootstrap
  • AngularJS v1.x
  • C3.js (for charting)

I will be posting the full instructions here over the weekend on how to get and install the code and metadata in your org.