ng-repeat Doesn’t Work

Posted on Dec 17, 2014


The title of this post may be a little misleading, as this post is really more about finding a way out of being stuck in asynchronous code purgatory. But the title is inspired by Google’s omniscient autocomplete search suggestion.

While picking up some legacy code as a part of a hackathon, I was having trouble getting ng-repeat to display anything helpful on the view. While searching for answers, Google kept suggesting the rather vague search phrase “ng-repeat doesn’t work”. In this post, I am going to explore why ng-repeat did not work in my particular case with using Firebase.

Refactoring the View

The reason for using ng-repeat was to reduce the redundancy in the view. There was a giant <table> for layout (!) with each section iterating through repeated properties of the model. This lead to a very large view with about 330 lines of hard-coded html that could be significantly reduced by about 90% by using ng-repeat to DRY it up.

However, when I applied ng-repeat, I could not get any of the properties of the model to display. For example this would produce nothing:

But this would show the entire Firebase object:

My First Clue

Angular was also throwing an error about not being able to call $apply before a previous invocation of $apply had resolved.

I took a look in the controller to see how we were getting the data, where I found multiple nuggets like this every time Firebase is queried or updated:

I realized that with multiple $scope.$apply references tied to fb.on("value", ...) all in the same controller, we were likely experiencing an asychronous issue. The second $scope.$apply was getting fired before the first one resolved with data returned from Firebase.

Simplify

I first commented out all those Firebase calls to just one call for the model I was trying to use with ng-repeat. Unfortunately, still no luck. I could load the main model, but no properties on the model. In fact, nothing was repeating at all. I actually had the ng-repeat on a

, but no rows were being repeated.

The thought occurred to me that this may still be an asynchronous issue. Maybe the html and ng-repeat was being loaded before Firebase came back with any data. If ng-repeat sees an empty object when it first loads, it won’t repeat any elements. Though I would assume that the view would update itself once the model updated because of Angular automagical data binding, asynchronous code can cause odd behavior.

AngularFire

First thing: let’s get rid of those $scope.$apply methods. There happens to be a lovely library called AngularFire that will sync data between your model and a Firebase instance.

After installing AngularFire with Bower and including the <script>, syncing the model and Firebase became simple and paved my path out of asynchronous code purgatory:

Success! Oh, wait …

Cool, now my ng-repeat is actually showing and repeating the properties of the model like I would expect…

… except that something is still not right. Some things repeat and some things don’t. After some frustrating experimentation, I found that this wasn’t working:

But this was working:

After some digging, I found that there seemed to be various reports of issues with using ng-repeat on a <tr>, like this one: https://github.com/angular/angular.js/issues/1459.

Okay, so that issue is two years old, and probably not applicable to my situation … but that still makes a lovely excuse to change all those <table>s to <div>s anyway! Bootstrap was already present, so it was easy enough to apply a grid.

After that I was able to compress the ~330 lines of html in the view to little more than the following by using a nested ng-repeat (some classes/styles and other stuff removed for clarity):

Submit a Comment

Your email address will not be published. Required fields are marked *