AngularJs with Visualforce Page and Remoting – Part 1

Content of the blog

This blog will show you how you can use AngularJS and Visualforce Remoting to display records onto your Visualforce Page. Other than AngularJS, I have used AngularStrap which is nothing but combination of AngularJS and BootStrap for UI purpose and ngTable for displaying records in pagination, ngTable is not required for part 1 because part 1 contains a simple table with less records which could have been done using simple bootstrap table and ngRepeat

Set Up

Add your required JS and CSS files into static resources and reference them on the Visualforce page, for example files required for this example are :-

CSS 
---- bootstrap.min.css
---- ng-table.min.css

JS

---- angular.min.js
---- angular-strap.min.js
---- angular-strap.tpl.min.js
---- ng-table.min.js
---- ui-bootstrap-tpls-0.11.0.js

You can always use additional CSS and JS for extended functionality. In addition please add your JS files at the end of the page because that will help your page to load faster

End Result

Account Details

Lets Begin

I hope you understand basic HTML page structure and apex page structure where HTML tag is kept inside apex page followed by rest of html tags.
Angular App Initialization, Inside your apex page tag.
Structure of the page

<apex:page showHeader="false" sidebar="false" docType="html-5.0" standardStylesheets="false" applyBodyTag="false" applyHtmlTag="false" controller="BlogOneController" >
<html ng-app="SampleApp" lang="en">
<head>
        <!-- Add CSS Files HERE -->		
	<script type="text/javascript">
	var myapp = angular.module('SampleApp',['ui.bootstrap','mgcrea.ngStrap','ngTable']);
	
        /*
           Add Factory code here -- FETCH_ACCOUNTS
        */ 

       /*
           Add Controller code here -- MainController
        */

	
	</script>
	</head>
<body ng-controller="MainController" >
--- Will come in next code snippet 

<!-- Add JS Files HERE -->
</body>
</html>
</apex:page>

In the above code snippet we are initializing Angular app by

<html ng-app="SampleApp" lang="en">

And loading the respective modules like AngularStrap,ngTable and bootstrap by adding

var myapp = angular.module('SampleApp',['ui.bootstrap','mgcrea.ngStrap','ngTable']);

In our example we are going to use two core components of AngularJS which is factory and controller. Factory will be responsible to fetch data from Salesforce via remoting and provide it to other Angular components whenever required.The factory code which is used for this example is below

myapp.factory('FETCH_ACCOUNTS', ['$q','$log', function($q,$log){
	var handleReq = function(remoteCall) {
        var defer = $q.defer();
	       remoteCall(
	          function(result, event) {
	            if(event.status) {
	              defer.resolve(result);
	            }
	            else {
	              $log.error(event.message);
	              defer.reject(event.message);
	            }
	          },
	          {escape:false, buffer: false}
	        );
	        return defer.promise;
	      }

	return {
        	getAllCustomers: function() {
          		return handleReq(BlogOneController.getAllAccounts);
        	}
      	}
}]);

How is factory working ? Factory is nothing but a method which holds data and return when it is called. In factory we are using $q which is service that helps you run functions asynchronously, and use their return values (or exceptions) when they are done processing (copied from AngularJS website).
Please understand the behaviour of $q service because it will be used a lot.
Remoting method in the controller

@RemoteAction
    global static List getAllAccounts() {    
    	return [SELECT Id,Name,BillingStreet,BillingCity,BillingState FROM Account];
    }

Second component is Controller where actual work is done. AngularJS follows MVC architecture very strictly where every controller is responsible for displaying,processing or changing UI based on the in scope items of a controller. Controller’s functional area in html page is limited to start and end tag of any div,body etc where ng-controller=”ControllerName” attribute is added, in our example scope of MainController is accross the body tag so MainController will be responsible for everything inside the body tag. In the controller make sure to pass all the components which are going to be used inside it for example our factory FETCH_ACCOUNTS otherwise it will throw error.The controller code which is used for this example is below

myapp.controller('MainController','$q','$log','$scope','FETCH_ACCOUNTS','ngTableParams',function($q,$log,$scope,FETCH_ACCOUNTS,ngTableParams){
			$scope.loadingH = true;
			var data = [];
			var promise = FETCH_ACCOUNTS.getAllCustomers();
			$scope.account_list = [];
			promise.then(function(response){
				data = response;
                        $scope.accountRecords.reload();
				$scope.loadingH = false;		
			},function(error){
				$log.error('ERROR' + JSON.stringify(error));
				$scope.loadingH = false;
			});
			
			$scope.accountRecords = new ngTableParams({
                             page: 1,            // show first page
                             count: 5
                                                 // count per page
                        }, {
            	             counts:[],
                             total: data.length, // length of data
                             getData: function($defer, params) {
                	     params.total(data.length);
                             $defer.resolve(data.slice((params.page() - 1) * params.count(), params.page() * params.count()));
                        }
       		       });
}]);

At first in the controller we are calling FETCH_ACCOUNTS which will return list of accounts, which is added to a local variable data var data = [];. Since we are using ngTable $scope.accountRecords is refering to ngTable component because of which the data will be displayed in a pagination format in table where ng-table=”accountRecords” attibute is added, for more details on ngTable please follow this link

The Front End

	<div class="panel panel-primary">
		  <div class="panel-heading">
		    <h3 class="panel-title">Account Information</h3>
		  </div>
		  <div class="panel-body">
		    	<table ng-table="accountRecords" class="table table-striped table-hover">
				  <thead>
				    <tr>
				      <th>#</th>
				      <th>Account Name</th>
				      <th>Street</th>
				      <th>State</th>
				    </tr>
				  </thead>
				  <tbody>
				    <tr ng-repeat="account in $data">
				      <td>{{$index+1}}</td>
				      <td>{{account.Name}}</td>
				      <td>{{account.BillingStreet}}</td>
				      <td>{{account.BillingCity}}</td>
				    </tr>
				  </tbody>
				</table>    
		  </div>
		</div>

I have used a bootstrap panel inside which again a bootstrap table with ngTable attribute, ng-repeat is to generate dynamically the table rows based on the list size.

This was the last piece of part 1

In part 2 I will show you how to add element and remove record form the table and the database

Advertisements

11 thoughts on “AngularJs with Visualforce Page and Remoting – Part 1

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s