Angular’s ng-repeat directive

Angular’s ng-repeat directive

October 8, 2015

Looping over object data in Angular is done by using the ng-repeat directive directly in your HTML. Here's how its done.

In the last article, Creating an AngularJS Controller, we learned how we can use our controller and the $scope object to place data in our view. Our object on the scope wasn’t repetetive, so there wasn’t any good reason for using ng-repeat. The object looked like this:

$scope.coffee = {
  roast: "Light Roast",
  brand: "Quick Check",
  size: "Small",
  fixings: "Cream and Sugar"
}

Data structure

Very often you’ll have an array of objects you’ll want to repeat in your HTML. Let’s create the array of objects.

//app.js with same 'brewitivity' module and same 'BrewController' from previous article on creating controllers...
var brewitivity = angular.module('brewitivity', []);
brewitivity.controller('BrewController', function($scope){

//new data structure
$scope.coffeePreferences = [
    {
      name: "Renee",
      roast: "Blonde Roast",
      brand: "Starbucks",
      size: "Venti",
      fixings: "Cream, Sugar, and Cinnamon"
    },
    {
      name: "Rebecca",
      roast: "Light Roast",
      brand: "Quick Check",
      size: "Small",
      fixings: "Hazelnut Creamer"
    },
    {
      name: "Rich",
      roast: "Pumpkin Spice",
      brand: "Quick Check",
      size: "Medium",
      fixings: "Cream and Sugar"
    }
  ];
});

Now we have 3 objects inside an array called coffeePreferences. I also have this data inside the same controller we created in the last article on creating controllers in order to provide you context of the entire app.js file.

Folder structure

Speaking of context, our entire folder structure would look like this.

//project root
  //app.js
  //index.html

The HTML

Here’s what the index.html file would look like to start off with.

<!--index.html-->
<!DOCTYPE html>
<html lang="en" ng-app="brewitivity"> 
<head>
  <title>ng-repeat demo</title>
</head>
<body>
  <h1>ng-repeat demo</h1>

  <!-- ng-repeat will go here -->
	
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.5/angular.min.js"></script>
  <script src="app.js"></script>
</body>
</html>

Okay, let’s add in the BrewController that matches our controller name in the app.js file.

<body>
  <h1>ng-repeat demo</h1>

  <!-- adding in the controller-->
  <div ng-controller="BrewController">
    
    <!-- ng-repeat will go here-->

  </div>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.5/angular.min.js"></script>
  <script src="app.js"></script>
</body>

So the ng-controller attribute with a value of BrewController has been added to the div thus making the BrewController in charge of that element and everything inside that element. Next, we have to add in the ng-repeat.

ng-repeat

<body>
  <h1>ng-repeat demo</h1>

  <!-- adding in the controller-->
  <div ng-controller="BrewController">
    
    <!-- creating the ng-repeat -->
    <p ng-repeat="person in coffeePreferences">{{person.name}}</p>

  </div>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.5/angular.min.js"></script>
  <script src="app.js"></script>
</body>

The p tag has the ng-repeat directive slapped on as an attribute. This says, I want to repeat this entire p tag based on the criteria I specify as the value of the attribute (person in coffeePreferences).

<p ng-repeat="person in coffeePreferences">{{person.name}}</p>

Focusing on the value of the ng-repeat directive, which has a value of person in coffeePreferences, there are really two parts: “person” and “coffeePreferences”. “coffeePreferences” is the name of our object from the controller. So we are saying we want to loop over that. This is a for each loop. The “person” part is a new variable I just came up with and can call it anything, including “alligator” if I wanted to. The important thing to note is that when I start writing the expression inside the curly brace syntax to pull in data, I have to use {{alligator.property}}, or in our example, {{person.property}}. I have to make sure the first part of that (i.e. person) matches what we specified as the variable in the first part of the ng-repeat directive. You won’t literally use “property” either. You’ll use the name of the property from the “coffeePreferences” object. Here’s an example of doing just that.

<p>{{person.name}} likes the {{person.roast}} from {{person.brand}}. Usually a {{person.size}} with {{person.fixings}} is preferable.</p>

And a codepen to give you full context of everything…

See the Pen ng-repeat directive (1of2) by Rich Finelli (@richfinelli) on CodePen.

Deeper Objects

The other thing that makes sense to learn is more involved, deeper objects. Let’s update the object in the app.js file to have an additional layer:

//app.js
var brewitivity = angular.module('brewitivity', []);
brewitivity.controller('BrewController', function($scope){
$scope.coffeePreferences = [
    {
      name: "Renee",
      coffee: {
        roast: "Blonde Roast",
        brand: "Starbucks",
        size: "Venti",
        fixings: "Cream, Sugar, and Cinnamon"
      }
      
    },
    {
      name: "Rebecca",
      coffee: {
        roast: "Light Roast",
        brand: "Quick Check",
        size: "Small",
        fixings: "Hazelnut Creamer"
      }
   },
   {
      name: "Rich",
      coffee: {
        roast: "Pumpkin Spice",
        brand: "Quick Check",
        size: "Medium",
        fixings: "Cream and Sugar"
      }
    }
  ];
});

All the same data is there, except everything makes more sense if we nest the coffee-related properties inside their own object called “coffee”. This makes the object more organized and I also think it makes our ng-repeat directive make more sense when we reference ‘person’ as the name of each object.

In order to use an Angular expression (the curly brace syntax) to access these properties, we’ll have to do so like so.

<p>{{person.name}} likes the {{person.coffee.roast}} from {{person.coffee.brand}}. Usually a {{person.coffee.size}} with {{person.coffee.fixings}} is preferable.</p>

Even deeper objects

To access deeper levels of the object you just use the dot notation to accomplish this. Here’s a slightly deeper example and how you would access the deeper properties.

//object
{
  name: "Rebecca",
  coffee: {
    roast: "Light Roast",
    brand: "Quick Check",
    size: "Small",
    fixings: {
      cream: "Hazelnut Creamer",
      sugar: false
  }
}
//expressions
{{person.coffee.fixings.cream}}
{{person.coffee.fixings.sugar}}

Video Recap

We veared a littled off course of ng-repeat, so here’s a video recap of what we discussed so far…


Codepen

Here’s a live example on Codepen just with the markup slightly different.

See the Pen ng-repeat directive (2of2) by Rich Finelli (@richfinelli) on CodePen.

Conclusion

Using ng-repeat is pretty darn useful. The thing that I like about it the most is it keeps your markup very minimal because your only creating a template. So if there’s 40 records in your data, your HTML file only has one instance of the markup necessary for it. Now there’s plenty more you can do with ng-repeat like filter the output that appears and we’ll get in to that in one of the next few articles. However, in the next part of my Angular Beginner Series is on using a very useful feature in Angular, the ng-if directive to conditionally load markup (yet to come).

Mastering CSS: Book by Rich Finelli
Mastering CSS, the Book! Flexbox, Layout, Animations, Responsive, Retina, and more!
Mastering CSS, 2nd Edition, video course by Rich Finelli
Mastering CSS, Second Edition: 47 videos on how to make websites like a boss! Flexbox, Animations, Responsive, Retina, and more!
  • http://www.consultwithmike.us/ Michael Perrenoud

    Very well written, in-depth post. The only thing I’d recommend is discussion the popular controller as + view model approach where you don’t hang things off the scope, but rather the instance of the controller. Great job!

Back to top