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.
I personally like to see an application in action before I dive into the code, so you can run the application yourself at http://angularjs-salesforce.herokuapp.com. The code is hosted at github for your forking pleasure but we'll walk through it in detail below.
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.
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).
Lastly is the workhorse of the application, the AccountsController. 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).
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.
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.
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.
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.
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.
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.
So there you have a nice little AngularJS application that you can reference for your next project! Enjoy!