Tuesday, July 11, 2017

Angular JS With Visualforce Page

https://apschwartz.wordpress.com/articles/using-angularjs-with-visualforce-remoting/

Angular JS With Visualforce Page

In this post, I am going to share the information how you can use Angular JS with Visualforceto display records onto your Visualforce Page

ANGULAR JS

Angular is a Google-produced MVC framework where you can generate web applications and maintain them. This is Javascript based component framework which is open source. Here Visualforce and Salesforce1 can be used for making Salesforce compatible with mobile and also for connecting people to the Salesforce data. AngularJS allows the easy development of Visualforce pages.
This Approach have its on limitations and advantages
1. AngularJS allows us to extend HTML vocabulary for dynamic applications.
2. This allows developers to create reusable components with more efficiency.
3. In salesforce we can use both AngularJS to build single page application.
4. Angular is most used when you want to developed an UI or front
5. ng-app Declares the root element of an AngularJS application,
6. ng-bind Sets the text of a DOM element to the value of an expression.
7. ng-model Similar to ng-bind, but establishes a two-way data binding between the view and the scope.
8. ng-controller Specifies a JavaScript controller class that evaluates HTML expressions.
9. ng-repeat Instantiate an element once per item from a collection.
To learn Basics of Angular JS ,please go through the link provided http://webkul.com/blog/starting-with-angularjs.

ADVANTAGES AND LIMITATIONS

Advantage
1. Two way Data Binding.
2. It support SPA(Single Page Application).
3. MVC(Model View Controller) pattern supported.
4. Less code
Limitations
1.AngularJS Its have some limitation when we handling huge amount of data.

ANGULAR JS WITH VISUALFORCE PAGE

Apex ::
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public with sharing class AngularWithVfPage {
  
        /**
         * Webkul Software.
         *
         * @category  Webkul
         * @author    Webkul
         * @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com)
         * @license   https://store.webkul.com/license.html
         */
 public static String getContacts() {
       return JSON.serialize([select id, name, email
           from contact ]);
   }
}
Visualforce::
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<apex:page showHeader="false" applyHtmlTag="false" docType="html-5.0" controller="AngularWithVfPage">
 <!--
        /**
         * Webkul Software.
         *
         * @category  Webkul
         * @author    Webkul
         * @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com)
         * @license   https://store.webkul.com/license.html
         */
         -->
<head>
   <meta charset="utf-8"/>
   <meta name="viewport" content="width=device-width, initial-scale=1"/>
   <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css"/>
   <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.11/angular.min.js"></script>
   <script>
      
     var App = angular.module('myApp', []);
  
     App.controller('myctrl', function ($scope) {  
     
         $scope.contacts = {!contacts}
     });
   </script>
</head>
<body ng-app="myApp" class="container" ng-controller="myctrl">
   <table class="table table-bordered">
     <tr>
       <th>Name</th>
       <th>Email</th>
       <th>Id</th>
     </tr>
     <tr ng-repeat="contact in contacts | filter:query">         
       <td>{{contact.Name}}</td>
       <td>{{contact.Email}}</td>
       <td>{{contact.Id}}</td>
     </tr>
   </table>
</body>
</apex:page>

OUTPUT

 AngularJsWithVisualforce

SUPPORT


How to develop Salesforce Visualforce apps using AngularJS ?


If you need to display Salesforce data to people other than those that have Salesforce accounts, Visualforce pages is the best way to go. It allows users to view, edit, or even add data without exposing the data to third party systems. For developers creating Visualforce apps is way easier than creating ad-hoc third party web apps that call upon Salesforce data.
Seeing the popularity of Visualforce, Salesforce started expanding upon the product and within few years of its launch we saw support for jQuery, brand new REST API, and ForceTK; a JS proxy calling library. However, the game changer for Salesforce and JavaScript development was when Salesforce allowed JavaScript remoting for Apex Controllers. JS remoting allowed you to access server side apex controller methods through JS directly. Along with Remote Objects, this allowed more flexibility and dynamic usage of Visualforce pages resulting in an even greater adoption of the tool. More and more organizations were depending upon Visualforce pages to display data to clients, partners, and other users now. This called for a more appealing UI for the Visualforce pages and frontend JS framework and libraries were naturally called into the fray. AngularJS being the most popular one was naturally the favorite for the task of creating eye candy dynamic Visualforce pages.
In our previous post we talked about why exactly AngularJS is great for creating Visualforce pages. In this post, we will talk about the HOWS. I am assuming that you have some general understanding of AngularJS framework, Salesforce Visualforce pages, and have experience with JavaScript.
For more info on any topic check out these links, they may help.
AngularJS – https://docs.angularjs.org/tutorial
Visualforce – https://developer.salesforce.com/trailhead/module/visualforce_fundamentals

How to use AngularJS in Visualforce?

JavaScript saw a renewed interest partially because of the success of its frameworks and partially because of greater need for a more visually appealing mobile friendly single page application. In Visualforce pages, the backend part is not that flexible but that’s because of the level of security that comes with Visualforce. The frontend part, on the other hand, is all yours. So frontend frameworks like AngularJS are greatly preferred to create organized, structured applications having good response times.
Now considering that each Visualforce app involves around CRUD (create, read, update, delete) operations on Salesforce data, there are three prevalent approaches for fetching and binding data from Salesforce to Visualforce controllers.
Creating JavaScript Remote objects and using it with Visualforce,
Using JSON,
And using ForceTK libraries along with AngularJS libraries.
The differences are subtle in small apps but as the complexity of your app grows, the difference would be more prominent.
The beauty of Visualforce pages is that you can start coding from the word go without opening or uploading multiple files to a server or such. So here I am assuming that you have an understanding about VF pages and can create a standalone page in the SFDC setup.
In this example, we are going to fetch a list of ‘Contacts’ saved in Salesforce in a tabular form and even add a simple search function highlighting two-way data binding of AngularJS.
Let’s take a look at the main Visualforce page code :
<apex:page showHeader="false" Controller="ContactsController">
   <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js">
   </script>
   <link rel="stylesheet"  href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" />
   
   <script type="text/javascript">
   var app = angular.module('MyApp',[]);  
   
   app.factory('VFRemotingFactory',function($q,$rootScope){  
       var factory = {};  
       factory.getData = function(searchText){  
           var deferred = $q.defer();  
           GetAllContactsByFilter(function(result){  
               $rootScope.$apply(function(){  
                   deferred.resolve(result);  
               });  
           }, searchText);  
           return deferred.promise;  
       }  
       return factory;  
   });
   
   function GetAllContactsByFilter(callback, searchText){  
       if(searchText == undefined)
       {
           searchText = '';
       }
       Visualforce.remoting.Manager.invokeAction(  
           '{!$RemoteAction.ContactsController.GetAllContactsByFilter}', searchText,
           callback,  
           {escape: false}  
       );
   }
   app.controller('myController',function($scope,VFRemotingFactory){  
       $scope.mcm = {};
       
       $scope.getFilteredData = function($event){
           if($scope.mcm.searchText.length > 1)
           {
               var searchTxt = $scope.mcm.searchText;
               VFRemotingFactory.getData(searchTxt).then(function(result){  
                   $scope.ContactData = result;  
               });
           }
           else
           {
               var searchTxt = $scope.mcm.searchText;
               VFRemotingFactory.getData().then(function(result){  
                   $scope.ContactData = result;  
               });
           }
           
       };
                $scope.Prafull = {};        
       VFRemotingFactory.getData().then(function(result){  
           $scope.ContactData = result;  
       });  
   });
   </script>
      
           <div ng-app="MyApp">
               <div ng-controller="myController">
                   <label>Search: <input ng-model="mcm.searchText" ng-keyup="getFilteredData($event)"/></label>
                   <table class="table">
                       <thead>
                           <tr>
                               <th>First Name</th>
                               <th>Last Name</th>
                               <th>Phone</th>
                               <th>Email</th>
                               <th>Title</th>
                               <th>Account Name</th>
                           </tr>
                       </thead>
                       <tbody>
                           <tr ng-repeat="contactVar in ContactData">
                               <td>{{contactVar.FirstName}}</td>
                               <td>{{contactVar.LastName}}</td>
                               <td>{{contactVar.Phone}}</td>
                               <td>{{contactVar.Email}}</td>
                               <td>{{contactVar.Title}}</td>
                               <td>{{contactVar.Account.Name}}</td>
                           </tr>
                       </tbody>
                   </table>
               </div>
           </div>
           <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
                <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
</apex:page>
Now let’s analyse this code. We started off by including a custom Salesforce apex
controller<https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_controller_custom.htm> for pulling contacts that we named very ingeniously “ContactsController”. This custom controller is also very simple.
public class ContactsController {
   @RemoteAction
   public static List<Contact> GetAllContactsByFilter(String searchText)
   {
       String searchString = '%' + searchText + '%';
       List<Contact> contactList = [SELECT FirstName, LastName, Phone, Email, Title, Account.Name FROM Contact where FirstName like :searchString];
       return contactList;
   }
}
As you may have guessed we are using JS Remoting to access to pass on our data.
We start off by creating our first AngularJS module that answers to name ‘MyApp’, var app = angular.module(‘MyApp’,[]). This app is referenced in the main body div through
<div ng-app="MyApp">
In our main body, we have created an input box that defines what we are going to display. By default, the content is ‘’ i.e. blank which triggers the app to display all contacts. As we start typing in the search box, it starts to filter out data based on the value in search box, in real-time, in the same page, without refreshing. This is the magic of two-way data binding.
Now from here on now we started to complicate things a little. The main angular controller that we again ingeniously named “myController” is the brains behind the module’s (or app) operations and we have included it in our nested div of the body.
We then created a module factory that invokes “GetAllContactsByFilter” function which in turn invokes Visualforceremote objects and our custom Visualforce controller ContactsController. This factory returns the list of contacts based on the search text, which by default is blank.
We created a scope object named ‘mcm’ that contains the model data that we input through Search input field. The $scope is the main magician that binds view with model.
The ng function ng-keyup=”getFilteredData($event) that we referenced in search input, triggers a new event whenever a key is entered in the search box. Triggering of this event results in automatic changing of model and in our example, automatic changing of view as well. You can restrict changing of view through a button.
Our AngularJS controller ‘myController’, triggers fetching of data based on the input value. For blanks it fetches all data so does it for typing only single alphabet. When the input string’s length becomes greater than one it filters out the data based on input string. The fetched data is stored in scope object ‘$scope.ContactData’ which in turn passes on data to ‘contactVar’ that finally displays data.
To summarize how AngularJS helped most in this really small and basic example:
  • The ng-keyup automatically trigger events based on user input. A custom function for this is tricky at best.
  • The two way data binding using custom code is full day work at best. We did it in 1 hour.
  • ng-repeat, the small function used to populate the table, a custom code for it will take at least 3-4 hours. We did in blink.
  • To add automatic filters we just have to add a line in the ng-repeat reference. For example, if we have to filter by an account we just have to add ng-repeat=”contactVar in ContactData | filter:account”. (Assuming account is the predefined variable).

An Even Simpler Approach

Now in the previous example, we have needlessly complicated things through module factory and Visualforceremoting. This use case can be achieved through a simpler code. Checkout the following code:
<apex:page standardStylesheets="false" sidebar="false"
   showHeader="false" applyBodyTag="false" applyHtmlTag="false"
   docType="html-5.0" controller="AngularDemoController">
<html lang="en" ng-app="demoApp">
<head>
   <meta charset="utf-8"/>
   <meta name="viewport" content="width=device-width, initial-scale=1"/>
   <title>Angular Demo</title>
   <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css"/>
   <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.11/angular.min.js"></script>
   <script>
     // define the app
     var demoApp = angular.module('demoApp', []);
     // add the controller
     demoApp.controller('DemoCtrl', function ($scope) {
         $scope.account = {!account}
         $scope.contacts = {!contacts}
     });
   </script>
</head>
<body class="container" ng-controller="DemoCtrl">
   <h1 style="color:Green">{{account.Name}}</h1>
   <p class="lead" style="color:Gray">
   {{account.BillingStreet}}<br/>
   {{account.BillingCity}}, {{account.BillingState}}
   {{account.BillingPostalCode}}
   </p>
    <b>Search</b>&nbsp;&nbsp;&nbsp;<input ng-model="query" /><br/><br/>
    
    
   <table class="table table-bordered">
     <tr>
       <th>Name</th>
       <th>Email</th>
       <th>Id</th>
     </tr>
     <tr ng-repeat="contact in contacts | filter:query">          
       <td>{{contact.Name}}</td>
       <td>{{contact.Email}}</td>
       <td>{{contact.Id}}</td>
     </tr>
   </table>
</body>
</html>
</apex:page>
Here is the code for controller:
global with sharing class AngularDemoController {
   // hardcode an account id for demo purposes
   static String accountId = '00128000003u3uK';
 
   global static String getAccount() {
       return JSON.serialize([select name, billingstreet,
           billingcity, billingstate, billingpostalcode
           from account where id = :accountId][0]);
   }    
 
   global static String getContacts() {
       return JSON.serialize([select id, name, email
           from contact where accountId = :accountId]);
   }
}
Here we are using the JSON approach, and using Salesforce’s inbuilt features like ‘!account’ and ‘!contact’ that automatically lookout for getAccount variable and method called in a custom controller. In this example, we have created an app to fetch contacts of an account whose ID we have hardcoded (I was a little lazy there).