-1

I have a project where I'm rendering a list of records to my HTML page, such as this example, which I've taken from:

https://www.w3schools.com/angular/ng_ng-repeat.asp

<body ng-app="myApp" ng-controller="myCtrl">

<h1 ng-repeat="x in records">{{x}}</h1>

<script>
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
    $scope.records = [
        "Alfreds Futterkiste",
        "Berglunds snabbköp",
        "Centro comercial Moctezuma",
        "Ernst Handel",
    ]
});
</script>

</body>

Now, all of this works fine when $scope.records is statically defined. But my problem is that I need to fetch my records from a REST API that is called from my service, such as this:

<script>
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope, myService) {
    myService.getRecords(function(records) {
        $scope.records = records.data;  // An array of records
    });
});
</script>

Obviously, when I call myService.getRecords(...), I pass it an anonymous function as a callback which gets executed asyc in a deferred manner.

I log the results of records so I know that my call works and my data is good and proper. But it seems as though $scope.records doesn't know it just has been updated.


Update: 2018.10.10 - Found it! Was looking for it but couldn't find the answer anywhere. Shortly after posting the question, I found it in two locations.

I'll post the links here as an answer for anyone looking for the same solution.

Jeach
  • 8,656
  • 7
  • 45
  • 58
  • 1
    Show us `getRecords` method implementation – Pankaj Parkar Oct 11 '18 at 19:55
  • If `getRecords` does not use the `$http` or `$q` providers, then AngularJS will not know to update the `$scope` variable – Pop-A-Stash Oct 11 '18 at 19:56
  • No, I haven't been using `$http` but rather `jQuery`. Not sure what `$q` is though. As mentioned, the problem wasn't with obtaining the data, it was on updating the page with the data. I was able to find `$scope.$apply()` and it worked. – Jeach Oct 11 '18 at 20:00

2 Answers2

3

The only reason you need $scope.$apply is becasue you are using angularjs the wrong way. And in your app, the use of jQuery to do api calls is the wrong way of doing angularjs.

Instead of using jQuery, use angularjs $http service. The service will take care of the syncronization with the angularjs scope and you will not be forced to manually use the $scope.$apply(). The service is included in the framework so the only thing you need to do is inject it in your service

Here's an example:

var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope, myService) {
    myService.getRecords().success(function(records) {
        $scope.records = records.data;  // An array of records
    });
});
app.factory('myService', function($http){
    return {
        getRecords: function() {
            return $http.get('yourapi/records');
        }
    };
});
Marcus Höglund
  • 16,172
  • 11
  • 47
  • 69
  • Thanks for sharing that information @Marcus, I will look into it. Although both ways look very similar in functionality, if I could remove a couple layers off the onion, it can't be a bad thing, right? And +1 for the code sample. – Jeach Oct 11 '18 at 21:11
  • @Jeach Np! removing jQuery from a angularjs application is never a bad thing:-) – Marcus Höglund Oct 12 '18 at 05:15
  • I've updated my code to do it your way. So far it seems to work without `jQuery`. Although, I've just realized something. I load my view (basic template), and then receive the data (via service) as discussed above. I need to invoke a third-party JS library after the data has been successfully rendered in the page. I figured that my `$scope.$on('$viewContentLoaded', function(event) { ... });` would get invoked but it's not. Should I just invoke my JS library call from within the service callback, or is there a better way? My lib is Packery. – Jeach Oct 17 '18 at 00:12
  • Here is an example of the code I'm suppose to call (once my data has been rendered in): `$('.grid').packery({ // options itemSelector: '.grid-item', gutter: 10 });` Yes, it is again, `jQuery`! :). – Jeach Oct 17 '18 at 00:13
  • Actually, calling the JS lib from the service doesn't work since there is a race condition ... why doesn't the `$viewContentLoaded'` event get called once the `$scope` has been updated? After-all, it knows the data has been updated?? – Jeach Oct 17 '18 at 00:17
  • I've tried `$timeout(function() { // Call jQuery code here for Packer }, 500);` and it works ... but I HATE code like that (based on timers). – Jeach Oct 17 '18 at 00:38
1

Was looking for it but couldn't find the answer anywhere. Shortly after posting the question, I found it in two locations.

I'll post the links here as an answer for anyone looking for the same solution.

The answer is $scope.$apply()

A great article here:

http://jimhoskins.com/2012/12/17/angularjs-and-apply.html

And someone had a similar question on SO here:

How can I tell AngularJS to "refresh"

Just not sure why I didn't see that Q&A in the list when you type your question. But regardless...

Jeach
  • 8,656
  • 7
  • 45
  • 58