Salesforce Visualforce Demo with AngularJs and Bootstrap

05:15 122 Comments A+ a-

Hi All
This is a sample demo which will guide you to Fetch, Create, Update, Delete Records by AngularJS on visualforce page. I have used the Bootstrap for the UI to make it device compatibility.


Watch here demo Click here
Unable to display content. Adobe Flash is required.

In this Tutorial we are going to learn following things :
1. How to Fetch Records
2. How to Create Record and Add to List
3. How to Update Record
4. How to Delete a Record

You first need to download or use the Angularjs file as below:
https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js

For using Angularjs we need to create "Application" and "Controller" on visualforce page as below :
<script type="text/javascript"> <!-- Name your application --> var myapp = angular.module('hello', []); var contrl=myapp.controller('ctrlRead', function ($scope, $filter) { }) </scrip>
All work will be under "Controller" visualforce page like below:

<body> <!-- =========== Binding Controller to Body of Page ============= --> <div ng-controller="ctrlRead"> <!-- Here you can write you code --> </div> </body>
 Now let's start "Fetch, Create, Update, Delete" Records by Angularjs in Apex Controller by using different methods. As below:
 
global class AngularJSDemoController{ public String AccountList { get; set; } //Subclass : Wrapper Class public class Accountwrap { //Static Variables public string id; public string name; public string Phone; public string Fax; public string Website; //Wrapper Class Controller Accountwrap() { Phone = ''; Fax = ''; Website = ''; } } //Method to bring the list of Account and Serialize Wrapper Object as JSON public static String getlstAccount() { List < Accountwrap > lstwrap = new List < Accountwrap > (); List < account > lstacc = [SELECT Id, Name, Phone,Fax,Website FROM Account order by name limit 10 ]; for (Account a: lstacc) { Accountwrap awrap = new Accountwrap(); awrap.id = a.id; awrap.name = a.name; if (a.Phone != null) { awrap.Phone = a.Phone; } if (a.Fax != null) { awrap.Fax = a.Fax; } if (a.Website != null) { awrap.Website = a.Website; } lstwrap.add(awrap); } return JSON.serialize(lstwrap); } @RemoteAction global static string createAccount(string name,string phone,string fax,string website){ String fax1 = fax == 'null' ? NULL : fax; String website1 = website == 'null' ? NULL : website; Account acc = new Account(name=name,phone=phone,fax=fax1,website=website1); insert acc; return acc.id; } @RemoteAction global static void updateAccount(string id,string name,string phone,string fax,string website){ String fax1 = fax == 'null' ? NULL : fax; String website1 = website == 'null' ? NULL : website; Account acc = new Account(name=name,phone=phone,id=id,fax=fax1,website=website1); update acc; } @RemoteAction global static void deleteAccount(string id){ Account acc = [select id from account where id =: id]; delete acc; } }
Now we will use these methods on page with angularjs like this :

<script> var myapp = angular.module('myapp', []); myapp.controller('MyController',function($scope,$filter){ $scope.items = {!lstAccount}; $scope.account = {}; $scope.account.Name =''; $scope.account.Phone =''; $scope.account.Website =''; $scope.account.Fax =''; $scope.account.Id =''; $scope.index=''; // Create Account $scope.create= function(){ if($scope.Name !== undefined && $scope.Phone !== undefined){ var Fax = $scope.Fax !== undefined ? $scope.Fax : 'null'; var Website = $scope.Website !== undefined ? $scope.Website : 'null'; Visualforce.remoting.Manager.invokeAction( 'AngularJSDemoController.createAccount', $scope.Name, $scope.Phone, Fax, Website, function(result, event) { if (event.status) { var newAccount = {}; // Add to list newAccount.name = $scope.Name; newAccount.Phone = $scope.Phone; newAccount.Fax = $scope.Fax; newAccount.Website = $scope.Website; newAccount.id = result; $scope.items.unshift(newAccount); // Reset Insert form Value $scope.Name = $scope.Phone = $scope.Fax = $scope.Website =''; $scope.$apply(); $('tr').eq(1).find('td').toggleClass( "bg-color"); setTimeout(function(){ $('tr').eq(1).find('td').toggleClass( "bg-color"); },3000) // Back to first tab $('#insertModal').modal('hide'); } else if (event.type === 'exception') { alert(event.message); } else { alert(event.message); } } ); }else{ // Show Error var msg =''; if( $scope.Name === undefined){ msg +='Name is Required! \n'; } if( $scope.Phone === undefined){ msg +='Phone is Required! \n'; } alert(msg); } } // Delete Account $scope.delete = function(index,id,obj){ ///$('.loadingDiv').hide(); $(obj).closest('tr').find('td').fadeOut(700); setTimeout(function(){ $scope.items.splice($scope.items.indexOf(index),1); $scope.$apply(); },900); Visualforce.remoting.Manager.invokeAction( 'AngularJSDemoController.deleteAccount', id, function(result, event) { if (event.status) { } else if (event.type === 'exception') { alert(event.message); } else { alert(event.message); } } ); } // Fill Value to Edit Form $scope.edit = function(index){ $scope.index = index; var detail = $scope.items[$scope.items.indexOf($scope.index)]; ///alert(JSON.stringify(detail)); $scope.account.Name =detail.name; $scope.account.Phone = detail.Phone; $scope.account.Fax =detail.Fax; $scope.account.Website = detail.Website; $scope.account.Id = detail.id; $('#updateModal').modal('show'); } // Update Account $scope.update = function(){ if($scope.account.Name !== undefined && $scope.account.Phone !== undefined){ var Fax = $scope.account.Fax !== undefined ? $scope.account.Fax : 'null'; var Website = $scope.account.Website !== undefined ? $scope.account.Website : 'null'; Visualforce.remoting.Manager.invokeAction( 'AngularJSDemoController.updateAccount', $scope.account.Id, $scope.account.Name, $scope.account.Phone, Fax, Website, function(result, event) { if (event.status) { $scope.items[$scope.items.indexOf($scope.index)].name = $scope.account.Name; $scope.items[$scope.items.indexOf($scope.index)].Phone= $scope.account.Phone; $scope.items[$scope.items.indexOf($scope.index)].Fax = $scope.account.Fax; $scope.items[$scope.items.indexOf($scope.index)].Website = $scope.account.Website; $scope.$apply(); $('#updateModal').modal('hide'); } else if (event.type === 'exception') { alert(event.message); } else { alert(event.message); } } ); }else{ // Show Error var msg =''; if($scope.account.Name === undefined){ msg +='Name is Required! \n'; } if($scope.account.Phone === undefined){ msg +='Phone is Required! \n'; } alert(msg); } } }) </script>

 Here is the full visualforce page code:
 
<apex:page showHeader="false" sidebar="false" standardStylesheets="false" controller="AngularJSDemoController"> <apex:remoteObjects > <apex:remoteObjectModel name="Account" jsShorthand="acc" fields="Name,Id,Phone"></apex:remoteObjectModel> </apex:remoteObjects> <html lang="en"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --> <title>Angularjs with Bootstrap</title> <!-- Bootstrap --> <link href="{!URLFOR($Resource.bootstrap,'css/bootstrap.min.css')}" rel="stylesheet" /> <link href="{!URLFOR($Resource.bootstrap,'css/bootstrap-theme.css')}" rel="stylesheet" /> <link href="https://netdna.bootstrapcdn.com/font-awesome/2.0/css/font-awesome.css" rel="stylesheet"/> <apex:includeScript value="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js"/> <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> <style> #account-box{ display:none } #account-list{ display:block } @media (max-width:400px){ h1{font-size:20px} #account-box{display:block} #account-list{ display:none } } .bg-color{background-color:#19BFE5;transition: opacity 500 ease-in-out;} </style> <script> var myapp = angular.module('myapp', []); myapp.controller('MyController',function($scope,$filter){ $scope.items = {!lstAccount}; $scope.account = {}; $scope.account.Name =''; $scope.account.Phone =''; $scope.account.Website =''; $scope.account.Fax =''; $scope.account.Id =''; $scope.index=''; // Create Account $scope.create= function(){ if($scope.Name !== undefined && $scope.Phone !== undefined){ var Fax = $scope.Fax !== undefined ? $scope.Fax : 'null'; var Website = $scope.Website !== undefined ? $scope.Website : 'null'; Visualforce.remoting.Manager.invokeAction( 'AngularJSDemoController.createAccount', $scope.Name, $scope.Phone, Fax, Website, function(result, event) { if (event.status) { var newAccount = {}; // Add to list newAccount.name = $scope.Name; newAccount.Phone = $scope.Phone; newAccount.Fax = $scope.Fax; newAccount.Website = $scope.Website; newAccount.id = result; $scope.items.unshift(newAccount); // Reset Insert form Value $scope.Name = $scope.Phone = $scope.Fax = $scope.Website =''; $scope.$apply(); $('tr').eq(1).find('td').toggleClass( "bg-color"); setTimeout(function(){ $('tr').eq(1).find('td').toggleClass( "bg-color"); },3000) // Back to first tab $('#insertModal').modal('hide'); } else if (event.type === 'exception') { alert(event.message); } else { alert(event.message); } } ); }else{ // Show Error var msg =''; if( $scope.Name === undefined){ msg +='Name is Required! \n'; } if( $scope.Phone === undefined){ msg +='Phone is Required! \n'; } alert(msg); } } // Delete Account $scope.delete = function(index,id,obj){ ///$('.loadingDiv').hide(); $(obj).closest('tr').find('td').fadeOut(700); setTimeout(function(){ $scope.items.splice($scope.items.indexOf(index),1); $scope.$apply(); },900); Visualforce.remoting.Manager.invokeAction( 'AngularJSDemoController.deleteAccount', id, function(result, event) { if (event.status) { } else if (event.type === 'exception') { alert(event.message); } else { alert(event.message); } } ); } // Fill Value to Edit Form $scope.edit = function(index){ $scope.index = index; var detail = $scope.items[$scope.items.indexOf($scope.index)]; ///alert(JSON.stringify(detail)); $scope.account.Name =detail.name; $scope.account.Phone = detail.Phone; $scope.account.Fax =detail.Fax; $scope.account.Website = detail.Website; $scope.account.Id = detail.id; $('#updateModal').modal('show'); } // Update Account $scope.update = function(){ if($scope.account.Name !== undefined && $scope.account.Phone !== undefined){ var Fax = $scope.account.Fax !== undefined ? $scope.account.Fax : 'null'; var Website = $scope.account.Website !== undefined ? $scope.account.Website : 'null'; Visualforce.remoting.Manager.invokeAction( 'AngularJSDemoController.updateAccount', $scope.account.Id, $scope.account.Name, $scope.account.Phone, Fax, Website, function(result, event) { if (event.status) { $scope.items[$scope.items.indexOf($scope.index)].name = $scope.account.Name; $scope.items[$scope.items.indexOf($scope.index)].Phone= $scope.account.Phone; $scope.items[$scope.items.indexOf($scope.index)].Fax = $scope.account.Fax; $scope.items[$scope.items.indexOf($scope.index)].Website = $scope.account.Website; $scope.$apply(); $('#updateModal').modal('hide'); } else if (event.type === 'exception') { alert(event.message); } else { alert(event.message); } } ); }else{ // Show Error var msg =''; if($scope.account.Name === undefined){ msg +='Name is Required! \n'; } if($scope.account.Phone === undefined){ msg +='Phone is Required! \n'; } alert(msg); } } }) </script> </head> <body ng-app="myapp"> <div class="container" ng-controller="MyController"> <!-- Loading Window --> <div class="loadingDiv" style="display:none"> <div style="position: fixed; top: 0; left: 0; right: 0; bottom: 0; opacity: 0.75; z-index: 100000;"> <div style="position:fixed;top:250px;height:100%;width:100%;"> <center> <img src="http://www.spotlightbusinessbranding.com/wp-content/plugins/use-your-drive/css/clouds/cloud_loading_256.gif" width="120px"/> </center> </div> </div> </div> <!-- Insert Modal --> <div class="modal fade" id="insertModal"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button> <h4 class="modal-title">New Account</h4> </div> <div class="modal-body"> <div class="col-md-12"> <form class="form-horizontal"> <div class="form-group"> <label>Name</label> <div class="input-group"> <span class="input-group-addon"> <i class="glyphicon glyphicon-user"></i> </span> <input type="text" class="form-control" placeholder="Name" ng-model="Name" /> </div> </div> <div class="form-group"> <label>Phone</label> <div class="input-group"> <span class="input-group-addon"> <i class="glyphicon glyphicon-earphone"></i> </span> <input type="text" class="form-control" placeholder="Phone" ng-model="Phone" /> </div> </div> <div class="form-group"> <label>Fax</label> <div class="input-group"> <span class="input-group-addon"> <i class="glyphicon glyphicon-print"></i> </span> <input type="text" class="form-control" placeholder="Fax" ng-model="Fax" /> </div> </div> <div class="form-group"> <label>Website</label> <div class="input-group"> <span class="input-group-addon"> <i class="glyphicon glyphicon-link"></i> </span> <input type="text" class="form-control" placeholder="Website" ng-model="Website" /> </div> </div> </form> </div> <div class="clearfix"></div> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> <input type="button" class="btn btn-success" ng-click="create()" value="Save" /> </div> </div><!-- /.modal-content --> </div><!-- /.modal-dialog --> </div><!-- /.modal --> <!-- Edit Modal --> <div class="modal fade" id="updateModal"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button> <h4 class="modal-title">Update</h4> </div> <div class="modal-body"> <div class="col-md-12"> <form class="form-horizontal"> <input type="hidden" ng-model="account.Id" /> <div class="form-group"> <label>Name</label> <div class="input-group"> <span class="input-group-addon"> <i class="glyphicon glyphicon-user"></i> </span> <input type="text" class="form-control" placeholder="Name" ng-model="account.Name" /> </div> </div> <div class="form-group"> <label>Phone</label> <div class="input-group"> <span class="input-group-addon"> <i class="glyphicon glyphicon-earphone"></i> </span> <input type="text" class="form-control" placeholder="Phone" ng-model="account.Phone" /> </div> </div> <div class="form-group"> <label>Fax</label> <div class="input-group"> <span class="input-group-addon"> <i class="glyphicon glyphicon-print"></i> </span> <input type="text" class="form-control" placeholder="Fax" ng-model="account.Fax" /> </div> </div> <div class="form-group"> <label>Website</label> <div class="input-group"> <span class="input-group-addon"> <i class="glyphicon glyphicon-link"></i> </span> <input type="text" class="form-control" placeholder="Website" ng-model="account.Website" /> </div> </div> </form> </div> <div class="clearfix"></div> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> <input type="button" class="btn btn-success" ng-click="update()" value="Save" /> </div> </div><!-- /.modal-content --> </div><!-- /.modal-dialog --> </div><!-- /.modal --> <div class="row"> <div class="col-md-12"> <h1>Angularjs with Bootstrap <div class="pull-right"> <button type="button" class="btn btn-sm btn-success" onclick="$('#insertModal').modal('show')"> <i class="glyphicon glyphicon-plus"></i> New </button> </div> <div class="clearfix"></div> </h1><hr/> <form class="form-horizontal"> <div class="form-group"> <label class="control-label col-md-2 col-md-offset-2">Search</label> <div class="col-md-4"> <input type="text" ng-model="search" class="form-control" /> </div> </div> <hr/> <div class="form-group"> <div class="col-sm-12"> <div id="account-box"><!-- Account Box List Start--> <div class="row" ng-repeat="account in items | filter:search"> <div class="col-xs-12"> <div class="thumbnail"> <div class="caption"> <dl> <dt>Name</dt> <dd>{{account.name}}</dd> <dt>Phone</dt> <dd>{{account.Phone}}</dd> <dt>Fax</dt> <dd>{{account.Fax}}</dd> <dt>Website</dt> <dd>{{account.Website}}</dd> </dl> <p> <button type="button" class="btn btn-sm btn-primary" title="Update" ng-click="edit(account)"> <i class="glyphicon glyphicon-pencil"></i> </button> <button type="button" class="btn btn-sm btn-danger" title="Delete" ng-click="delete(account,account.id,$event.target)"> <i class="glyphicon glyphicon-trash"></i> </button> </p> </div> </div> </div> </div> </div><!-- Account Box List End--> <div class="panel panel-primary" id="account-list"><!-- Account List Start--> <div class="panel-heading">Accounts</div> <div class="panel-body" style="padding:0px"> <table class="table table-striped table-bordered" style="margin:0"> <thead> <tr> <th>Name</th> <th>Phone</th> <th>Fax</th> <th>Website</th> <th>Action</th> </tr> </thead> <tbody> <tr ng-repeat="account in items | filter:search"> <td>{{account.name}}</td> <td>{{account.Phone}}</td> <td>{{account.Fax}}</td> <td>{{account.Website}}</td> <td width="100"> <button type="button" class="btn btn-sm btn-primary" title="Update" ng-click="edit(account)"> <i class="glyphicon glyphicon-pencil"></i> </button> <button type="button" class="btn btn-sm btn-danger" title="Delete" ng-click="delete(account,account.id,$event.target)"> <i class="glyphicon glyphicon-trash"></i> </button> </td> </tr> </tbody> </table> </div> </div><!-- Account List End --> </div> </div> </form> </div> </div><!-- Main Row End --> </div><!-- Container End --> <!-- jQuery (necessary for Bootstrap's JavaScript plugins) --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <!-- Include all compiled plugins (below), or include individual files as needed --> <script src="{!URLFOR($Resource.bootstrap,'js/bootstrap.min.js')}"></script> </body> </html> </apex:page>

For public demo click
http://mufiz12ka4-developer-edition.ap1.force.com/AngularjsWithBootstrap

Feel free to use the code and try it out. Provide me your valuable feedback:

Thanks
Shaikh Mufiz