Using AngularJS with Salesforce Remote Actions

Angular JS with Salesforce Remote Actions

Using Angular JS with Remote Actions

Nowadays Angular JS is a great front end framework in order to manipulate DOM and do many more things throughout the DOM. Here I'm going to describe how to use Angular JS with Visualforce and apex remote actions.

There are two ways to add angular into the Visualforce page. We can add angular code in the Visualforce page itself or we can add angular code to the static resource.

Advertisement

If we use angular code in the Visualforce page itself it will break the single page application concept and also it’s hard to maintain the code. We cannot have multiple Visualforce pages in one angular app. Once rendering a new Visualforce page there only have one angular application for each Visualforce page. In this post, I'm going to use a static resource to write angular code. And also I'm going to use welkin suite for as the IDE for the development. Because from welkin suite we can modify the static resource bundle (But currently we cannot add js files for partial pages to a static resource, the only thing what we can do is modify the js files, but it is great because we can compare the modifications with salesforce org) and also welkin suite is really familiar to me because welkin has the same look and feel like Visual Studio.  When we using Static Resource we have to consider one thing of the sales force governor limit. That is static resource is limited to 5 MB. If you using more than 5MB for the static resource bundle you have to make separate bundles that have less than 5MB size after zipping.

You can download welkin suite from https://welkinsuite.com/downloads/

Creating Static resource for Angular Bundle

Hope you have some knowledge of Angular developments. And I'm going to use the UI route for the routing mechanism for the app. Initially, you have to create the folder structure for the angular static resource bundle as below. Here I'm using two controllers (firstController.js) and one service (firstService.js) and two partial HTML (firstView.html, secondView.html) pages and app.js file. You can create this folder structure with the empty js and empty HTML files and add those files to the static resource.

app - controllers - firstController.js - services -firstService.js - views -firstView.html -secondView.html app.js

If you going to use welkin, create a new project by giving your salesforce credentials and security token. Or else you can use MavensMate or another tool to edit Static Resource.

Now you need to create a Visualforce page to make the root page container for the angular app. I have created the page as AngularTest.page.Then create an apex class to expose the remote actions. I have created the class as AngularRemoteClass. Here I'm going to demonstrate a really simple angular application in order to call a remote action. So I have written a RemoteAction method as 'angularRemoteFunction'. It will return Boolean true value once you give any name as method parameters. According to the requirement, you can make the modifications to the RemoteAction. Here I will keep it as a very simple for the demo.

public class AngularRemoteClass {
    @RemoteAction public static Boolean angularRemoteFunction(String name) { 
        return true; 
    }
}

Below I have noted the code of the apex page. Here I have added angular.js file and angular UI route js files from the CDN. If you like you can add those angular files to the static resource (and that is the recommended way to add external resources).  I have created the angular app as MyApp. And I have added <ui-view></ui-view> tags to change HTML partials dynamically from the angular. And also here I have added the SitePrefix javascript variable because from the static resource we cannot directly call to the apex global variables. So I have added it to the js global variable and then I can call for the SitePrefix from the static resource js files. (AngularApp is the static resource bundle name) var SitePrefix="{!URLFOR($Resource.AngularApp)}/app/" ;

After the UI view tag, I have referenced to the app.js file, firstController.js, and firstService.js file from the static resource.

<apex:page controller="AngularRemoteClass" showheader="false" sidebar="false" doctype="html-5.0" standardstylesheets="false"> 
    <html lang="en">
        <head title="MyApp"> 
            <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script> 
            <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.18/angular-ui-router.min.js"></script> 
            <script type="text/javascript">
                var SitePrefix="{!URLFOR($Resource.AngularApp)}/app/";
            </script>
        </head>
        <body ng-app="MyApp">
            <ui-view></ui-view>
            <!-- Add JS Files HERE --> 
            <script src="{!URLFOR($Resource.AngularApp)}/app/app.js"></script>
            <script src="{!URLFOR($Resource.AngularApp)}/app/controllers/firstController.js"></script> 
            <script src="{!URLFOR($Resource.AngularApp)}/app/services/firstService.js"></script> 
        </body>
    </html>
</apex:page>

app.js file

I have used ui-route for the routing, therefore I have injected $stateProvider to the config.

(function () { 
    'use strict';
    angular.module('MyApp', [ 'ui.router', 'MyApp.services', 'MyApp.controllers']) .config(function ($stateProvider, $urlRouterProvider) {
        $urlRouterProvider.otherwise('/default');
        $stateProvider .state('default', { url: '/default', views: { '': { templateUrl: SitePrefix + 'views/firstView.html', controller: 'firstController' } } })
    })
    angular.module('MyApp.services', []); 
    angular.module('MyApp.controllers', []); 
}());

firstController.js file In here I have injected myFirstService factory method to call Apex Remote Action. And I’m calling to ‘authenticateUser’ method from 'myFirstService' service and I’m passing 'prasad' as the name parameter.

(function() {
    'use strict'; 
    angular.module('MyApp.controllers').controller('firstController', ['$scope' , 'myFirstService' , function ($scope , myFirstService ) {
        myFirstService.authenticateUser({ name : 'prasad' } ,
        //success calla back
        function(data) { console.log(data); },
        //error call back
        function(data) { console.log(data); });
    }]);
}());

firstService.js

If your org using a namespace then you have to use that namespace when you calling to the Remote Action. 'prasadRevenueS' is my namespace. I’m calling to the apex remote action by calling to  ‘Visualforce.remoting.Manager.invokeAction’ method.

(function(){
    'use strict';
    angular.module('MyApp.services').factory('myFirstService' , ['$rootScope' , '$q' ,  function ($rootScope , $q ){
        var myAPI = {}; 
        myAPI.authenticateUser = function (param, successCallBack, errCallBack) {
            var promise = $q.defer().promise;                
            Visualforce.remoting.Manager.invokeAction('prasadRevenueS.AngularRemoteClass.angularRemoteFunction', param, function(result, event){
                if (event.status) {
                    console.log('#### Result ####');
                    console.log(result);
                    $rootScope.$apply(function() {
                        promise.then(successCallBack(result));
                    });
                } else if (event.type === 'exception') {
                    errCallBack(event);
                } else { 
                    errCallBack(event);
                } 
            }, {escape: false});
            return promise; 
        };
        return myAPI;
    }]);
}());

Finally, you will see the true result from your browser log. Please note this post is only to understand how to make the flow with angular and remote actions, therefore I kept everything in the simple form. Please share your ideas on this.

Thanks,

Prasad

Popular Salesforce Blogs