Skip to content

Instantly share code, notes, and snippets.

@afawcett
Last active November 25, 2022 08:58
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save afawcett/6a38c589e3ae18ad2d16d4ee98e00b17 to your computer and use it in GitHub Desktop.
Save afawcett/6a38c589e3ae18ad2d16d4ee98e00b17 to your computer and use it in GitHub Desktop.
Salesforce London World Tour 2016: Lightning Out: Components on Any Platform
<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes"
controller="AddressFinderController" access="global">
<aura:attribute name="accounts" type="Account[]"/>
<aura:attribute name="contacts" type="Contact[]"/>
<aura:registerEvent name="AddressInfo" type="c:AddressInfo"/>
<div class="slds-form--stacked">
<div class="slds-form-element">
<label class="slds-form-element__label" for="inputSample2">Account Search</label>
<div class="slds-form-element__control">
<input id="inputSample2" class="slds-input" type="text" placeholder="Enter partial account name" onkeyup="{!c.onSearchKeyChange}" />
</div>
</div>
<fieldset class="slds-form-element">
<legend class="form-element__legend slds-form-element__label">Accounts</legend>
<div class="slds-form-element__control">
<aura:iteration items="{!v.accounts}" var="account">
<label class="slds-radio">
<input type="radio" id="{!account.Id}" name="account" onchange="{!c.onAccountSelected}"/>
<span class="slds-radio--faux"></span>
<span class="slds-form-element__label">{!account.Name}</span>
</label>
</aura:iteration>
</div>
</fieldset>
<fieldset class="slds-form-element">
<legend class="form-element__legend slds-form-element__label">Contacts</legend>
<div class="slds-form-element__control">
<aura:iteration items="{!v.contacts}" var="contact">
<label class="slds-radio">
<input type="radio" id="{!contact.Id}" name="contact" onchange="{!c.onContactSelected}"/>
<span class="slds-radio--faux"></span>
<span class="slds-form-element__label">{!contact.Name}</span>
</label>
</aura:iteration>
</div>
</fieldset>
</div>
</aura:component>
<aura:application extends="ltng:outApp" access="global" >
<ltng:require styles="https://lo-demo-london2016-summer-dev-ed.lightning.force.com//resource/slds103/assets/styles/salesforce-lightning-design-system-ltng.css" />
<aura:dependency resource="c:AddressFinder"/>
</aura:application>
public class AddressFinderController {
@AuraEnabled
public static List<Account> findByName(String searchKey) {
String name = '%' + searchKey + '%';
return [SELECT id, name FROM Account WHERE name LIKE :name LIMIT 50];
}
@AuraEnabled
public static List<Contact> findContactsByAccountId(Id accountId) {
return [SELECT id, name FROM Contact WHERE AccountId = :accountId LIMIT 50];
}
@AuraEnabled
public static AddressInfo getAddressInfo(Id contactId) {
Contact contact = [select Id, Name, AccountId from Contact where Id = :contactId];
Account account = [select Id, Name, BillingStreet, BillingCity, BillingState, BillingPostalCode, BillingCountry from Account where Id = :contact.AccountId];
AddressInfo address = new AddressInfo();
address.AddressLine1 = contact.Name;
address.AddressLine2 = account.BillingStreet;
address.AddressLine3 = account.BillingCity;
address.AddressLine4 = account.BillingPostalCode;
address.AddressLine5 = account.BillingCountry;
return address;
}
}
({
onSearchKeyChange : function(cmp, event, helper) {
helper.searchKeyChange(cmp, event);
},
onAccountSelected : function(cmp, event, helper) {
helper.accountSelected(cmp, event);
},
onContactSelected : function(cmp, event, helper) {
helper.contactSelected(cmp, event);
}
})
({
searchKeyChange: function (cmp, event) {
var action = cmp.get("c.findByName");
action.setParams({ "searchKey": event.target.value });
action.setCallback(this, function(a) {
cmp.set("v.accounts", a.getReturnValue());
});
$A.enqueueAction(action);
},
accountSelected : function(cmp, event) {
var action = cmp.get("c.findContactsByAccountId");
action.setParams({ "accountId": event.target.id });
action.setCallback(this, function(a) {
cmp.set("v.contacts", a.getReturnValue());
});
$A.enqueueAction(action);
},
contactSelected : function(cmp, event) {
var contactId = event.target.id;
var action = cmp.get("c.getAddressInfo");
action.setParams({ "contactId": contactId });
action.setCallback(this, function(a) {
console.log(a.getReturnValue());
var compEvent = $A.get("e.c:AddressInfo");
compEvent.setParams({"address" : a.getReturnValue() } );
compEvent.fire();
});
$A.enqueueAction(action);
}
})
global class AddressInfo {
@AuraEnabled
global String AddressLine1;
@AuraEnabled
global String AddressLine2;
@AuraEnabled
global String AddressLine3;
@AuraEnabled
global String AddressLine4;
@AuraEnabled
global String AddressLine5;
}
<aura:event type="APPLICATION" access="global">
<aura:attribute name="address" type="c.AddressInfo"/>
</aura:event>
/**
* Creates a menu entry in the Google Docs UI when the document is opened.
*
* @param {object} e The event parameter for a simple onOpen trigger. To
* determine which authorization mode (ScriptApp.AuthMode) the trigger is
* running in, inspect e.authMode.
*/
function onOpen(e) {
DocumentApp.getUi().createAddonMenu()
.addItem('Start', 'showSidebar')
.addItem('Log Out', 'logout')
.addToUi();
}
/**
* Runs when the add-on is installed.
*
* @param {object} e The event parameter for a simple onInstall trigger. To
* determine which authorization mode (ScriptApp.AuthMode) the trigger is
* running in, inspect e.authMode. (In practice, onInstall triggers always
* run in AuthMode.FULL, but onOpen triggers may be AuthMode.LIMITED or
* AuthMode.NONE.)
*/
function onInstall(e) {
onOpen(e);
}
/**
* Opens a sidebar in the document containing the add-on's user interface.
*/
function showSidebar() {
var driveService = getDriveService();
if (!driveService.hasAccess()) {
var authorizationUrl = driveService.getAuthorizationUrl();
var template = HtmlService.createTemplate(
'<a href="<?= authorizationUrl ?>" target="_blank">Authorize</a>. ' +
'Reopen the sidebar when the authorization is complete.');
template.authorizationUrl = authorizationUrl;
var page = template.evaluate();
DocumentApp.getUi().showSidebar(page);
} else {
var ui = HtmlService.createHtmlOutputFromFile('Sidebar')
.setTitle('Lightning Out Demo')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
DocumentApp.getUi().showSidebar(ui);
}
}
function getDriveService() {
// Create a new service with the given name. The name will be used when
// persisting the authorized token, so ensure it is unique within the
// scope of the property store.
return OAuth2.createService('salesforce')
// Set the endpoint URLs, which are the same for all Google services.
.setAuthorizationBaseUrl('https://login.salesforce.com/services/oauth2/authorize')
.setTokenUrl('https://login.salesforce.com/services/oauth2/token')
// Set the client ID and secret, from the Google Developers Console.
.setClientId('yourclientid')
.setClientSecret('yourclientsecret')
// Set the name of the callback function in the script referenced
// above that should be invoked to complete the OAuth flow.
.setCallbackFunction('authCallback')
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getUserProperties())
}
/**
* Runs when the add-on is installed.
*
* @param {object} request HTTP request
*/
function authCallback(request) {
var driveService = getDriveService();
var isAuthorized = driveService.handleCallback(request);
if (isAuthorized) {
return HtmlService.createHtmlOutput('Success! You can close this tab.');
} else {
return HtmlService.createHtmlOutput('Denied. You can close this tab');
}
}
/**
* Logoff
*/
function logout(){
OAuth2.createService('salesforce')
.setPropertyStore(PropertiesService.getUserProperties())
.reset();
}
/**
* Adds the given address to the document
**/
function addAddresss(address) {
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
body.appendParagraph(address.AddressLine1);
if(address.AddressLine2!=null) {
body.appendParagraph(address.AddressLine2);
}
if(address.AddressLine3!=null) {
body.appendParagraph(address.AddressLine3);
}
if(address.AddressLine4!=null) {
body.appendParagraph(address.AddressLine4);
}
if(address.AddressLine5!=null) {
body.appendParagraph(address.AddressLine5);
}
}
/**
* Returns the Salesforce oAuth token to the client
*/
function getSalesforce() {
var salesforce = {
token: getDriveService().getAccessToken()
};
return salesforce;
}
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<!-- Lightning component goes here! -->
<div class="slds" id="locmp"></div>
<!-- Include the Lightning Out API from Salesforce -->
<script src="https://lo-demo-london2016-summer-dev-ed.lightning.force.com/lightning/lightning.out.js">
</script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
</script>
<script>
/**
* On document load, retrieve Salesforce oAuth token and initialize Lightning Out!
*/
$(function() {
google.script.run.withSuccessHandler(init)
.withFailureHandler(showError).getSalesforce();
});
/**
* Callback function that provides access to the Salesforce connection details
*
* @param {Object} salesforce The Salesforce oAuth details
*/
function init(oauth) {
// Load Lighting Out and the Lightning Component
$Lightning.use("c:AddressFinderApp",
function() {
// Create the component and wire up an event handler to the AddressInfo event
$Lightning.createComponent("c:AddressFinder", { }, "locmp",
function(){
$A.eventService.addHandler({ "event": "c:AddressInfo", "handler" : addressInfoEvent});
}
);
},
"https://lo-demo-london2016-summer-dev-ed.lightning.force.com",
oauth.token);
}
/**
* Handles the Address event from the Lightning Component
**/
function addressInfoEvent(event) {
// Address details from the AddressFinder AddressInfo event
var address = event.getParam("address");
// Update the document
google.script.run.withFailureHandler(showError).addAddresss(address);
}
/**
* Inserts a div that contains an error message after a given element.
*
* @param msg The error message to display.
* @param element The element after which to display the error.
*/
function showError(msg, element) {
var div = $('<div id="error" class="error">' + msg + '</div>');
$(element).after(div);
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment