StackOverflow_23983322: angularjs-checkbox-filter

Illustration of answer to http://stackoverflow.com/questions/23983322/angularjs-checkbox-filter.

by epinapala

HTML

<script src="http://code.angularjs.org/1.2.16/angular.min.js"></script>
<div ng-controller="myCtrl">
    <div ng-repeat="(prop, ignoredValue) in wines[0]" ng-init="filter[prop]={}">
        <b>{{prop | capitalizeFirst}}:</b><br />
        <span class="quarter" ng-repeat="opt in getOptionsFor(prop)">
            <b><input type="checkbox" ng-model="filter[prop][opt]" />&nbsp;{{opt}}</b>
        </span>
        <hr />
    </div>
    <div ng-repeat="w in filtered=(wines | filter:filterByProperties)">
        {{w.name}} ({{w.category}})
    </div>
    <hr />
    Number of results: {{filtered.length}}
</div>

CSS

.quarter {
    display:   inline-block;
    min-width: 25%;
}

JavaScript

var app = angular.module('myApp', []);
app.controller('myCtrl', function ($scope) {
    $scope.wines = [
        { name: "Wine A", category: "red" },
        { name: "Wine B", category: "red" },
        { name: "wine C", category: "white" },
        { name: "Wine D", category: "red" },
        { name: "Wine E", category: "red" },
        { name: "wine F", category: "white" },
        { name: "wine G", category: "champagne"},
        { name: "wine H", category: "champagne" }    
    ];
    $scope.filter = {};

    $scope.getOptionsFor = function (propName) {
        return ($scope.wines || []).map(function (w) {
            return w[propName];
        }).filter(function (w, idx, arr) {
            return arr.indexOf(w) === idx;
        });
    };

    $scope.filterByProperties = function (wine) {
        // Use this snippet for matching with AND
        var matchesAND = true;
        for (var prop in $scope.filter) {
            if (noSubFilter($scope.filter[prop])) continue;
            if (!$scope.filter[prop][wine[prop]]) {
                matchesAND = false;
                break;
            }
        }
        return matchesAND;
/**/
/*
        // Use this snippet for matching with OR
        var matchesOR = true;
        for (var prop in $scope.filter) {
            if (noSubFilter($scope.filter[prop])) continue;
            if (!$scope.filter[prop][wine[prop]]) {
                matchesOR = false;
            } else {
                matchesOR = true;
                break;
            }
        }
        return matchesOR;
/**/
    };
    
    function noSubFilter(subFilterObj) {
        for (var key in subFilterObj) {
            if (subFilterObj[key]) return false;
        }
        return true;
    }
});

app.filter('capitalizeFirst', function () {
    return function (str) {
        str = str || '';
        return str.substring(0, 1).toUpperCase() + str.substring(1).toLowerCase();
    };
});