[SalesForce] New to Using Remote Action with Angular JS

I need help with this code can someone please suggest what must I do to bring the names of contacts in the table on page load. What I have done is I saw this

http://www.saaspie.com/2015/03/27/developing-simple-application-in-salesforce-using-angular-js/

and implemented Angular JS from there and then replaced the code for fetching contacts list using remote actions. I am getting the contacts array in a variable that is declared out of scope but not loading on page as I want

my page code is

<apex:page controller ="SampleRemoteActionWithAngularJS" standardStylesheets="false" applyHtmlTag="false" sideBar="false" showHeader="false">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js">
</script>
<script>
var app = angular.module('MyApp',[]);
var mytestvar;
app.controller('myController',['$scope',function($scope)
{
$scope.ctdata;
$scope.ContactData =  Visualforce.remoting.Manager.invokeAction(
        '{!$RemoteAction.SampleRemoteActionWithAngularJS.getContacts}',
         function(result, event) 
         {
            console.log(result);
            $scope.ctdata = result;
            mytestvar = result;

         }); 
      }]);
</script>
<div ng-app="MyApp">

<div ng-controller="myController">
<table>
<thead>
<th>
Name
</th>
</thead>
<tr ng-repeat="Contactvar in ctdata">
<td>{{Contactvar.Name}}</td>
</tr>
<tbody >
</tbody>
</table>
<button onclick ="alert(JSON.stringify(mytestvar))">Show Alert !!!</button>
</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>

and apex code is

public with sharing class SampleRemoteActionWithAngularJS {

    @RemoteAction
    public static list<contact> getContacts()
    {
        return [SELECT Id, Name FROM contact limit 10];
    }
}

Please help I want to learn this

Best Answer

Short answer: you need to use $scope.$apply to force angularJs to reload the elements. So your code should look like this:

$scope.ContactData =  Visualforce.remoting.Manager.invokeAction(
        '{!$RemoteAction.SampleRemoteActionWithAngularJS.getContacts}',
         function(result, event) 
         {
            $scope.$apply(function() {
              console.log(result);
              $scope.ctdata = result;
              mytestvar = result;
            });
         }); 
      }]);

The longer answer: AngularJS watches all the elements in the watchList. It gets updated every time it notices anything has changed in the watchList. It knows the things changed by subscribing itself to all the regular angular methods so usually it updates automatically. Even during ajax callback methods, if you use the angular way of doing it, it is still fine.

But the exception is none-angular methods. Javascript remoting is definitely one example. So you need to manually notify angularJs to reRender the page in the callBack function. In this case, use $scope.$apply.

Note: AngularJS might seem to be easy in the first instance, but it is not as easy when you try to master it... It is like marriage. If you are just into the template engine and small stuffs like sorting, filtering, etc.(Like I did) Consider using a template engine and a lightweight sorting js library, not the whole monolithic AngularJS.