Directives With Filters

http://angularjs.org/

by bmleite

HTML

<script src="http://underscorejs.org/underscore-min.js"></script>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.0/bootstrap.min.js"></script>
<div ng-controller="MyCtrl">
    <h1>Tags</h1>
    <ul>
        <li ng-repeat="tag in model.tags">{{tag.name}} {{tag._active}}</li>
    </ul>
    <h1>Toggles</h1>
    <div toggle-buttons data="model.tags"></div>

    <h1>Results (simple)</h1>
    <ul>
        <li ng-repeat="datum in model.data | filter:tagFilter">{{datum.name}}</li>
    </ul>

    <h1>Results (directive)</h1>
    <div fancy-display="model.data" filter="tagFilter"></div>
</div>

CSS

@import url('http://twitter.github.com/bootstrap/assets/css/bootstrap.css');

JavaScript

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

// Controller supplies data and handles the lists of tags
function MyCtrl($scope) {
    $scope.model = {};
    $scope.model.data = [
        {"name": "test1", "tags": ["tag1", "tag2"]},
        {"name": "test2", "tags": ["tag2", "tag3"]},
        {"name": "test3", "tags": ["tag1", "tag3"]}
    ];
    $scope.$watch('model.data', function() {
        var tagNames = $scope.model.data.reduce(function(tags, datum) {
            return _.union(tags, datum.tags);
        }, []);
        $scope.model.tags = $.map(tagNames, function(tagName, index) {
            return {"id": tagName, "name": tagName, "_active": true};
        });
    }, true);

    $scope.$watch('model.tags', function() {
        $scope.model.activeTags = $scope.model.tags.reduce(function(selected, tag) {
            if (tag._active) {
                selected.push(tag.name);
            }
            return selected;
        }, []);
    }, true);    

    $scope.tagFilter = function(datum) {
        return intersects($scope.model.activeTags, datum.tags);
    };

    // Returns true if there is any intersection between input arrays
    function intersects(a, b) {
      if ((a == null) || (b == null)) {
        return false;
      }
      var i = 0, len = a.length;
      for (i; i < len; i++) {
        if (b.indexOf(a[i]) !== -1) {
          return true;
        }
      }
      return false;
    }
}

// toggleButtons directive handles updating the model when the tags are toggled
myApp.directive('toggleButtons', function() {
  return {
    scope: { data: '='},
    controller: function($scope, $element, $attrs, $location) {
      $scope.toggle = function(data, itemId) {
        for (var i=0; i < data.length; i++) {
          if (data[i].id == itemId) {
            data[i]._active = !data[i]._active;
            break;
          }
        }
      };
    },
    template: "<button class='btn active' " +
      "data-toggle='button' " +
      "ng-repeat='datum in data' "...