Part 1 covered the fundamentals. Now let's go deeper into the parts that actually make or break a real AngularJS application: filters done right, the services abstraction, and understanding the digest cycle.

Filters

Filters format data for display without modifying the underlying model. They can be used in templates or injected into controllers and services.

Built-in Filters

<!-- Currency -->
{{ price | currency:'$' }}         <!-- $1,234.56 -->

<!-- Date -->
{{ timestamp | date:'dd MMM yyyy' }}  <!-- 30 Jan 2016 -->

<!-- LimitTo -->
{{ items | limitTo:5 }}            <!-- first 5 items -->

<!-- OrderBy -->
<li ng-repeat="u in users | orderBy:'name'">{{u.name}}</li>

<!-- Filter (search) -->
<li ng-repeat="u in users | filter:searchText">{{u.name}}</li>
โš ๏ธ Performance warning: View filters run on every digest cycle. With large arrays, this creates significant overhead. For big datasets, apply filters in the controller instead of the template, and cache the result.

Custom Filter

app.filter('truncate', function() {
  return function(text, length) {
    if (!text) return '';
    return text.length > length ? text.substring(0, length) + '...' : text;
  };
});
{{ article.body | truncate:120 }}

Services, Factories & Providers

All three are singletons โ€” created once, shared across the app. The difference is in how you define them.

Factory โ€” functional style

app.factory('ItemService', function() {
  var items = [];
  return {
    list: function() { return items; },
    add: function(item) { items.push(item); }
  };
});

Service โ€” class style

app.service('ItemService', function() {
  var items = [];
  this.list = function() { return items; };
  this.add = function(item) { items.push(item); };
});

Provider โ€” configurable before app starts

app.provider('Config', function() {
  var debug = false;
  this.setDebug = function(val) { debug = val; };
  this.$get = function() {
    return { isDebug: function() { return debug; } };
  };
});

// In config phase โ€” before app runs
app.config(function(ConfigProvider) {
  ConfigProvider.setDebug(true);
});
Use Provider when you need to configure a service before the application starts. Use Factory for most other cases โ€” it's the most flexible. Use Service when you prefer class-based patterns.

The Digest Cycle

Understanding the digest cycle is essential for avoiding mysterious bugs and performance issues in AngularJS.

AngularJS tracks model changes through dirty checking. On each digest cycle, it compares the current value of every watched expression to its previous value. If anything changed, the cycle runs again โ€” until nothing changes (or until the limit is hit and it throws an error).

Key rules

// Triggering digest from outside Angular (e.g. a jQuery callback)
element.on('click', function() {
  $scope.$apply(function() {
    $scope.someModel = 'updated';
  });
});

Part 3 will cover custom directives in depth, compile vs link functions, and transclusion.