AngularJS - Introduction to repeat controls and filtering

As part of a series of articles on the basics of AngularJS I am going to write a small example of one of the common features on Angular that I use every day. Its called 'ng-repeat'.

Link: Online Demo

What are they?

ng-repeats can be used in conjunction with any HTML elements. Most commonly they are used to layout data in a tabular format or to populate lists, but equally they can be used to populate choices for radio buttons, select boxes or just divs laying out data results. The important thing to understand is that ngRepeats are essentially a short handed way of binding your data to an element in your model and having AngularJS iterate over the data to produce something for someone to consume in the UI.

Requirements

Firstly you need some data. Angular is going to assume that the data you are going to use is an array of objects. Mostly this is going to consist of some data you have got from an API call but it could be anything. In the usual fashion we will bind this to a our scope as below. Note that the data we get back from our local file 'sample'json' is bound to $scope.items.

var myApp = angular.module('myApp', []);

myApp.controller('MyRepeat', function($scope, $http) {  
 // a scope function to load the data
    $scope.loadData = function () {
        $http.get('sample.json').success(function (data) {
            //Bind the returned data to the scope.
            $scope.items = data;
        });
    };
});

OK so we now have our binding in our model, we now need to display this information in our view. For this we set up a 'controller' in the usual fashion and then use our ng-repeat tag to instruct Angular to iterate over the associated data and lay it out in the format of our choice. You could consider this your HTML template. NB: Angular does allow you to re-use templates using directives but we will come onto this in another article. For now we just add the following HTML to our page (or 'view').

 <div class="container" ng-controller="MyRepeat">
//Table has been prettified using bootstrap css classes
       <table class="table table-bordered table-striped">
      <thead>
        <tr>
          <th>#</th>
          <th>Name</th>
          <th>Age</th>
          <th>Country</th>
          <th>Company</th>
        </tr>
      </thead>
      <tbody>
        <tr ng-repeat="person in items">
          <td>{{$index+1}}</td>
          //Dot notation takes the values from each object in the scoped 'items' 
          <td>{{person.Name}}</td>
          <td>{{person.Age}}</td>
          <td>{{person.Country}}</td>
          <td>{{person.Company}}</td>
        </tr>
      </tbody>
    </table>
  </div>
The Resulting Table



So now we not only have a representation of our data in a nice tidy layout, we also have it bound to our data model. The advantage of using this method is that we can now dynamically update the table when we update our data. A good example of this is having your data laid out as above and including an input form mapped to your data above it. Then when a user submits some new data and it gets added to your bound data, the table updates instantly. Similarly if you include a button as part of your HTML template you can allow users to remove items from your data by clicking them and the UI will reflect these changes straight away.

A step further

AngularJS has some nice features which can be used in conjunction with ngRepeat. In this example we are going to look at two of them. If you want to read about the rest of them you can go to the documentation. Firstly we will look at a very helpful property that you can attach directly to your ng-repeat tag. Its called 'filter'. What it allows you to do is, not surprisingly, filter the dat that is displayed on your bound element. This is great in itself but where it becomes really handy is if you bind your filter to a scoped element, such as an input field. You can then allow a user to type into an input field to filter the data set being displayed in the UI. The simplicity of implementing this is incredible and the speed with which the results are filtered (even over a large data set) is very impressive.

Another feature I am going to mention is one which I hope will highlight the flexibility of an ngRepeat. Often when using frameworks you are bound to it wholesale with little interaction with behaviour of the code once its been passed the object. With an ngReapt you still have the ability to manipulate the output HTML based on the values belonging to the object being iterated over. So you can apply a conditional argument to the ngReapet very easily. Using the concept of users being easily able to pick out data from a large data set, you could add an ngClass tag to your template and display a data element in a different way to highlight it. This allows you to highlight data but to keep it in context with the rest of your data set. For example in our data set of people you could highlight everyone with the name of 'Daniel'.

The final code snippet below demonstrates this and uses a second input field for you to enter a value in in order to see all matching values in the country field highlighted in red.

<div class="container" ng-controller="MyRepeat">  
    <form class="form-horizontal well">
      <div class="form-group">
        <label for="search" class="col-sm-3 control-label">
  Filter</label>
        <div class="col-sm-9">
          <input name="search" class="form-control" ng-model="search" />
        </div>
      </div>
      <div class="form-group">
        <label for="search" class="col-sm-3 control-label">Highlight Country</label>
        <div class="col-sm-9">
          <input name="showMe" ng-model="highlightCountry" class="form-control" />
        </div>
      </div>
    </form>


    <table class="table table-bordered table-striped">
      <thead>
        <tr>
          <th>#</th>
          <th>Name</th>
          <th>Age</th>
          <th>Country</th>
          <th>Company</th>
        </tr>
      </thead>
      <tbody>
        <tr ng-repeat="person in items | filter: search" ng-class="{red: person.Country.toLowerCase() == highlightCountry.toLowerCase()}">
          <td>{{$index+1}}</td>
          <td>{{person.Name}}</td>
          <td>{{person.Age}}</td>
          <td>{{person.Country}}</td>
          <td>{{person.Company}}</td>
        </tr>
      </tbody>
    </table>
  </div>

Here is a link to a plnkr. Its worth noting that ngRepeats are also very useful for thinkgs like image carousels, selection boxes and many, many more UI items once you have got the hang of the basic theory behind them.

If you feel like making your application look really smooth then you might want to consider adding a toaster notification when new data has been added/loaded. Mark Barton has written a nice article on how you can do this here.