A couple of weeks ago I attend the Building Enterprise Apps Rapidly with Salesforce Mobile Packs webinar with Pat Patterson and Raja Rao. While I think it was a good introduction to AngularJS in general it seemed to lack any specific Force.com integration (probably by design). So for anyone looking to get started with AngularJS and Force.com I put together a small demo application that creates, updates and displays Account records from a Salesforce.com org. Feel free to clone the repo for your own use, learn from the code or pick it apart to make it better.
The application is technically a Rails application but Ruby is only used for the CRUD operations with Salesforce.com. This eliminates the CORS issues with multiple domains. I used the awesome Restforce gem and expose everything as JSON in the controller. Perhaps a better, pure JavaScript solution would have been to use Node for the backend with the equally as awesome nforce package but I’ll leave that to another blog post. I started out using CoffeeScript but switched back to straight JavaScript as I think it is easier for most people to grok.
So let’s jump into the application. The github repo has the instruction for installing and running the application both locally and on Heroku. First get the application up and running and then continue reading below.
Let’s start with the Rails portion of the application since it is fairly simple. The routes.rb file simply declares our RESTful accounts resource (for communicating with Force.com) and directs all requests to the index route in the applcation controller. This route will start our Angular app for us.
1
2
3
4
AngularSalesforceDemo::Application.routes.drawdo
resources :accounts
root to: 'application#index'end
We need to add some Angular directives to our application.html.erb to make the application work. First, on line 2 we add ng-app=”app” to auto-bootstrap our application called (wait for it……) “app”! We also add ng-view to line 11 so that the view will change based upon the current route requested.
Here is the ApplicationController that renders the single page for our application. We just need a place to launch from and this happens to be it. So we have no view (thus :nothing => true) but we still want the layout (since it has the app bootstrap code).
1
2
3
4
5
6
7
8
9
class ApplicationController <ActionController::Base
protect_from_forgery
# We'll just use this as a launch point for our Appdef index
render :layout=>'application', :nothing=>trueendend
Lastly is the workhorse of the application, the AccountController. This controller performs all of the interaction with Force.com using the Restforce gem (the private ‘client’ method on line #43) and is designed to only return JSON data. The code is commented below but there are actions to query for account records (index), return a specific account by id (show), create a new account in Salesforce.com (create) and update an existing account in Salesforce.com (update).
class AccountsController < ApplicationController
respond_to :jsondef index
# simply return the query as json
respond_with client.query('select id, name, type, billingstate
from account order by lastmodifieddate desc limit 5')enddef show
# return the requested record as json
respond_with client.query("select id, name, type, billingstate
from account where id = '#{params[:id]}'").firstend# create a new record in salesforce. Use the following command for testing:# curl -v -H "Content-type: application/json" -X POST # -d '{"name": "some test name"}' http://localhost:3000/accountsdef create
# create the account in salesforce and get the new id
id = client.create!('Account', Name: params[:name], Type: 'Prospect',
BillingState: 'NY')# query for the newly created account
account = client.query("select id, name, type from account
where id = '#{id}'").first# return the resource so it can be added to the collection
respond_with(account, :status=>:created,
:location=> account_url(account))enddef update
# update only two of the fields in salesforce and return the record
client.update!('Account', Id: params[:account][:Id],
Name: params[:account][:Name],
Type: params[:account][:Type])
respond_with client.query("select id, name, type, billingstate
from account where id ='#{params[:account][:Id]}'")end
private
# define the restforce client and authenticatedef client
client = Restforce.new:username=> ENV['SFDC_USERNAME'],
:password=> ENV['SFDC_PASSWORD'],
:client_id=> ENV['SFDC_CLIENT_ID'],
:client_secret=> ENV['SFDC_CLIENT_SECRET'],
:host=> ENV['SFDC_HOST']
client.authenticate!
client
endend
The app.js file is the launcher for our entire application and defines our module called “app”. It contains our routing information which tells Angular which controller and view template to load based upon the route being requested (home page with the list of accounts or account details page). We also inject the ngResource dependency so that our application can take advantage of our RESTful resources in our rails controller.
'use strict';
/*
This is our main launch point from Angular. We will put anything to do with the
general well being of our app in this file. For now it will basically just contain
the routing information.
Ourmodule will be called "app".
*/
angular.module('app', ['ngResource'])
.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider){$routeProvider
.when('/', {
controller: 'AccountListCtrl',
templateUrl: '/assets/angular/templates/index.html'})
.when('/accounts/:id', {
controller: 'AccountDetailCtrl',
templateUrl: '/assets/angular/templates/details.html'})
.otherwise({redirectTo: '/'});
}]);
The services directory has a single models.js file which defines our Account resource to communicate with Force.com via the RESTful routes. We pass in the URL to the resource, “/accounts”, and an optional :id parameter. Angular will use the id parameter if present and call the show action in the controller, otherwise it will call the index route to return all accounts. Since, by default, the Angular $resource does not support an update method, we need to declare an additional action (i.e., update) that we can call on the Account resource.
Since controllers and views work hand-in-hand, let take a look at them together as part of the route.
Home Page
When the user visits the root page in our application (i.e., “/”), Angular loads the AccountListCtrl controller and the index.html view template. In line #5 we inject the Account resource into our controller so that our RESTful routes are available. Line #6 defines a scope variable called “accounts” which contains an array of Accounts by returning ‘/accounts.json’ via Account.query().
We also define an “add” function that is used when the user submits the form to create a new Account. This function creates a new Account resource, calls $save on the resource (POSTs the data to our create action in our controller to insert it into Salesforce.com), adds the new Account resource to the array of all “accounts” and then clears out the form for reuse.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
'use strict';
var app = angular.module('app');
app.controller('AccountListCtrl', function($scope, Account){$scope.accounts = Account.query();
$scope.add = function(){
var account = new Account({name:$scope.newAccount.name});
account.$save(function(){$scope.accounts.push(account)$scope.newAccount = {}});
}});
In the index.html template, the ng-controller directive declares the controller to be used for the section of code (you can use multiple controllers in the same template). We first have a form that allows the user to add a new Account. The ng-submit directive defines the function in the controller to execute when the form is submitted. The ng-model directive tells Angular to do two-way data binding with our newAccount object so that it can easily be used in our controller.
Next we simply output our five Accounts from Salesforce.com using the ng-repeat directive.
<h1>AngularJS Demo with Salesforce.com</h1><span class="lead" style="padding-bottom:10px">By Jeff Douglas (<a href="http://www.twitter.com/jeffdonthemic" target="_blank">@jeffdonthemic</a>). You can find the accompanying blog post at <a href="http://blog.jeffdouglas.com/?p=4800" target="_blank">blog.jeffdouglas.com</a>. This demo connects to Salesforce.com using Ruby on Rails. The application allows you to create, update and display Account records from Salesforce.com.</span><div ng-controller="AccountListCtrl"><h2>Create a New Account</h2><form name="frm" ng-submit="add()"><input type="text"class="input-xlarge" ng-model="newAccount.name" required><br/><button type="Submit"class="btn btn-primary">Add Account</button></form><br/><h2>Last 5 Modified Accounts</h2><table class="table table-striped"><thead><tr><th>Account Name</th><th>Type</th><th>State</th></tr></thead><tbody><tr ng-repeat="account in accounts"><td><a href="#/accounts/{{account.Id}}">{{account.Name}}</a></td><td>{{account.Type}}</td><td>{{account.BillingState}}</td></tr></tbody></table></div>
Account Details & Edit Page
The final part of our application is the account details page. The AccountDetailCtrl controller is loaded and the details.html template is displayed when the details route (/accounts/:id) is requested. This page has a little more going on as it not only displays the details of the page but also provides the functionality for updating the Account in Salesforce.com.
Once again, we inject the Account resource into the controller and fetch the Account from Salesforce.com with “/accounts/:id.json” via Account.get(). We also set the $scope variable mode to ‘display’ so that the page initially displays the details of the Account instead of the edit form. The update function at the bottom PUTS our data to “/accounts/:id.json” via Account.update() to update the Account in Salesforce.com.
'use strict';
var app = angular.module('app');
app.controller('AccountDetailCtrl', function($scope, $routeParams, Account){$scope.account = Account.get({id:$routeParams.id});
$scope.mode = 'display';
$scope.edit = function(){$scope.mode = 'edit';
}$scope.cancel = function(){$scope.mode = 'display';
}$scope.update = function(){$scope.mode = 'display';
Account.update({id:$routeParams.id}, $scope.account, function(){// performs some operation when the callback completes like error checking
console.log('Callback completed!');
});
}});
The details.html template has two sections; one for displaying the Account and a form for updating the account. These sections display based upon the value of ‘mode’ in the ng-show directive. The update form uses the ng-model directive to display the values of the model attributes. The two-way binding updates the model immediately. For example, each change you make to the Account name in the text field will immediately update the Account name at the top of the page as they are both bound to the same model.
On May 19th some of us from Appirio are doing Tough Mudder in Jacksonville as part of “Team Ruiz” to raise money for a couple of reasons. I’ve given a lot to the Salesforce developer community so I’m hoping in turn I can persuade some people step up and pay it forward after hearing this story.
So that’s my son on the left. He’s an arabic-speaking Army Special Operations sergeant heading back for his second deployment to Afghanistan in the next couple of days (literally). The tattoo on his chest is for his good friend, 22 year old Sergeant Clint Ruiz, that was killed Afghanistan on October 25, 2012 in this blue on green incident. He’s survived by a wife and small son.
We are running the Tough Mudder to raise money for Wounded Warrior Project (hopefully my son will never need it) and also raise money for Clint’s Ruiz’s 2 year old son’s college fund. I’m hoping that you’ll donate some money to at least one (if not both) of the causes below.
Donate to College Fund
If you’d like to donate money to Clint Ruiz’s son’s college fund, please send it to my Paypal account (jeff@jeffdouglas.com) and I’ll see that it makes it to his parents. I’ll personally match each dollar that is donated.
First of all I love asynchronously processing in Salesfoce. We use it all the time at CloudSpokes. I don’t actually mean that the @future annotation should die, per se, but I think there is a better approach. I see the annotation rising from the ashes like a phoenix!!! If you agree please take some time and vote for my idea below.
The @future annotation is typically used in one of two ways:
Create a better user experience – Let’s say you have a process that whenever an Opportunity is created a number of calculations are made on a custom object. However, since these calculations don’t affect what the user is currently doing, why make them wait as these calculations are made? Apex methods marked with the @future annotation are executed asynchronously when Salesforce has available resources. A better solution is to create the Opportunity and call your calculations asynchronously so that the user does not have to wait for them to finish processing.
Calls to external web services – As Force.com applications have taken more of centralized role in the enterprise application architecture, there is an evolving need to keep external systems in sync. Suppose you have a requirement (not uncommon) that each time you update a contact you have to call an external webservice to update the contact in SAP, Siebel, etc. Since callouts are prohibited in triggers, you need to call an Apex class with a @future method that is marked as (callout=true).
The @future annotation is a great tool but with great power comes great responsibility. Here are some things you need to keep in the back of your mind when using them:
Depending on the number of licenses you have you may bump into some org-wide limits as Salesforce imposes a limit on the number of future method invocations. You can only have 200 method calls per full Salesforce user license or Force.com App Subscription user license, per 24 hours. This is understandable (i.e., limits != evil) but what if you are doing data loading/cleanup or have installed a managed package that puts you over your limit, you simply have to wait for you invocations to reset and somehow reprocess those items that failed.
No more than 10 method calls per Apex invocation. This one is understandable as well but I’ve seen a number of projects where we’ve had to implement some other type of system (polling for instance) because the limitation makes this approach technically impossible. The example is, suppose you have a trigger that updates 11 contact records (or 200!) and needs to make a callout for each record. You are screwed unless you have the luxury of being able to rewrite your external webservice to accept a collection of records.
You cannot call a method annotated with @future from a method that also has the @future annotation. We’ve run into this a number of times as the class hierarchy grows in larger projects. You want to reuse an existing class but what happens if it already calls a @future method? Or what happens if an managed package contains a @future method?
The parameters for a @future method must be primitive data types, arrays of primitive data types, or collections of primitive data types. Not a big deal as you can typically pass the IDs of the affected records and query for them. But doesn’t that seem like a waste of resources if the Apex that calls the @future method already holds these records? It would be great if you could pass a collection of sObject or Apex objects.
It’s difficult to orchestrate processes with @future annotations because these methods do not necessarily execute in the same order they are called.
Unit tests are difficult to write. Period.
Here’s my alternative: Apex Queue
I know that you can “work around” most of these issues and believe me most developers do. But wouldn’t it be far less effort and more efficient to deprecate the @future annotation and replace it with an “Apex Queue”? Quese are not rocketsurgery and have been around for quite a long time. Let’s embrace them for Force.com development. “My kingdom for a queue!!” I say!
Now I’m neither an Engineer at Salesforce nor do I play one on TV but here’s what I think implementing a queue would involve. I’m sure there are technical implications that I am unaware of but I’ll give it a shot.
Apex invocations are simply passed to the queue and processed sequentially when resources are available (i.e., it’s a queue). I typically don’t care when a process is kicked off but just that it did run and in a certain sequence. Would be great to have some sort of history similar to batch jobs.
Higher limits for callouts would be awesome but there is a tipping point here. You can’t allow unlimited callouts but perhaps 200 callouts per invocation would be awesome to accomidate triggers.
Ability to pass complex objects, sObjects and primitives as method parameters to methods in the queue.
Bulk processing with ability to call Batch Apex. I would love to push a call to the queue that in turn kicks off a batch process in the same thread.
No more issues with calling a @future method from a @future method as each call would be replaced by sending the Apex invocation to the queue.
Much easier to test as you don’t have to worry about startTest() and stopTest().
It’s an understatement to say that I’m a fan of Code School. I love the way they’ve blended professional video screen casts, live coding in the browser, and gamification to make learning fun again. The music is a little campy sometimes but overall I’m addicted to it as you can see from my report card.
Yesterday they released a new course sponsored by Google to really dig into Chrome’s DevTools. I’ve always tinkered with DevTools but have never become a power user. I was always looking for some sort of tutorial to explain everything to me. Well here it is! The course involves beginning and advanced DOM and style manipulation, working with the console, debugging JavaScript, memory profiling and improving performance. The best part is that the course is free to everyone! No need to purchase a subscription… but I would if I were you.
Continuous Integration (CI) for Force.com projects has been a popular topic lately. There are a number of blog post that describe the benefits and how you should go about doing it. However, after we discussed it on our #DifferentSpokes podcast last week, we received a number of emails asking for help on getting CI up and running. So I put together a short video on the process using Jenkins.
Earlier this week we broadcast our third episode of #DifferentSpokes with a special guest, Josh Birk from Salesforce.com. If you missed it, it was a really entertaining episode with some interesting questions from Twitter. Obviously we focused on Salesforce.com related topics such as:
Some of the highlights of the Spring ’13 release and why the new Tooling API rules!
The growing tensions in the Salesforce Chicago office over differing opinions on breakfast foods
Josh’s love affair with anything related to JavaScript
His recent CI work with Jenkins for Salesforce.com
Why JavaScript Remoting makes creating dynamic applications in Force.com fun again
How to make Backbone.js and Visualforce play nicely
His preferences on Java Script debuggers, IDEs, modern text editors, old school text editors, distribution of linux and JavaScript templating frameworks.
Our next episode will be focusing on Angular.js so don’t miss that!
So my customer success for CloudSpokes on Heroku went live today with a link in their developer newsletter.
Pretty good stuff on how the CloudSpokes community members built the CloudSpokes site on Database.com and Heroku. We honestly don’t think it would have been possible to do with any other platforms in such a short amount of time.
So I ran across this issue a couple of months ago and forgot to blog about it for my reference and anyone else that runs across this problem. So here’s the issue, I have an Apex class scheduled in production that runs another Apex class. I’ve made some changes to this second class and need to deploy it to production. Before you do that, for Force.com platform requires you to delete the scheduled job for that class since they are related.
No problem. So I deleted the scheduled class, pushed my new code to production (passes all tests! w00t!) and went back to schedule this class to run and saw this error:
I went and looked at the class and noticed that it was no longer valid:
So here’s how you fix the issue so that the class can be scheduled. You have to simply have to make salesforce recompile the classes and then it will be available to schedule.
I must publicly confess my love with the Force.com Streaming API. (Don’t tell my wife.) Last September I wrote a blog post entitled, Node.js Demo with Force.com Streaming API & Socket.io that showed how to stream events from Saleforce.com to the browser using Node.js. It was a pretty cool app if you are familiar with Node.js.
Then at Dreamforce ’12 I did an Un-Conference session called, “Log Force.com Events in REALTIME with Papertrail” which was a knock-off but showed how to create an external logger for Salesforce using the Force.com Streaming API. Pretty slick stuff but again in Node.js.
Well I’ve found a much easier way to use the Force.com Streaming API than my previous attempts thanks to the Restforce ruby gem. According to the docs “… the Restforce gem makes implementing pub/sub with Salesforce a trivial task”. A bold statement but entirely true.
So I put together a sample rails app that you can use as a starter with the Force.com Streaming API. Just fork this repo, watch the video below and then follow the simple, step-by-step instructions on the repo to get started. The demo app streaming events from a “Log__c” custom object to the rails app with in turn uses Papertrail as a logger.
Here’s the file that does the heavy lifting for you. It connects to your org with the Restforce client, starts listening for events on the “LogEntries” channel and then once it receives it, outputs it to Papertrail through “puts”.
123456789101112131415161718192021222324252627
require'restforce'
require'faye'
# Initialize a client with your username/password.
As one of the committers for the Databasedotcom gem, I follow most of the other committers to see what they are working on. I was pleasantly surprised a few months back when Eric Holmes started pushing code for a project called “Restforce“. I nearly fell out of my seat when I read that it was billed as a “lighter weight alternative to the databasedotcom gem”.
We’ll, we been using it for a couple of months now to build our new CloudSpokes API, and I have to say that it’s a pretty impressive gem. Eric has been consistently refactoring and adding features and it extremely responsive. I’ve submitted a few issues and he’s gotten back to me immediately. Check out the repo for complete details but here’s a high level overview of the features:
A clean and modular architecture using Faraday middleware and Hashie::Mash’d responses. Add your own middleware to Restforce!
Multiple OAuth flows.
Support for interacting with multiple users from different orgs.
Support for parent-to-child relationships.
Support for aggregate queries.
Optional bang CRUD methods (create, update, upsert, destroy) that raise salesforce.com exceptions
Support for the Streaming API with EventMachine
Support for blob data types (uploading files)
Support for GZIP compression.
Support for custom Apex REST endpoints. Winning!!
Support for decoding Force.com Canvas signed requests.
He’s written a number of sample applications in rails and sinatra so if you are writing ruby app that you would like to integrate with salesforce.com, I would highly recommend you check out Restforce.
I'm a Senior Technical Consultant at Appirio specializing in cloud-based applications using Salesforce.com, Google App Engine and VMware.
You should be a foster and/or adoptive parent. I'm both and it's fun!! Ask me how.
Buy My Books!
By Jeff Douglas & Wes Nolte
By Jeff Douglas &Kyle Roche
Favorite Quotes
"Any sufficiently advanced technology is indistinguishable from magic."
"Those who say it cannot be done should not interrupt the person doing it."