Filter

The filter module provides components that allow users to select filter criteria. These components create a button to expose filtering options, a modal footer to display buttons that apply and clear filters, and a summary to indicate which filters have been applied.

The filter modal footer component wraps the bb-modal-footer directive to provide filter-specific buttons that apply and clear filters.

  • bb-filter-modal-footer — Specifies the buttons to display in the filter modal's footer.
    • bb-filter-modal-apply — Specifies a function to be called when users click the button to apply filters.
    • bb-filter-modal-clear — Specifies a function to be called when users click the button to clear filters.

Filter button

The filter button component creates a button that exposes filtering options.

  • bb-filter-button — Creates a button that kicks off a function to expose filtering options.
    • bb-filter-button-on-click — Specifies a function to be called when users click the filter button.
    • bb-filter-button-active(Optional.) Specifies whether the filter button should be given active indication. This property should be set when indication of filtering is not visible to the user, such as when a filter summary is not shown. (Default: false)

Filter summary

The filter summary component indicates which filters have been applied.

  • bb-filter-summary — Displays summary items for the filters that users apply.
    • bb-filter-summary-item — Displays an entry in the summary for a filter that has been applied.
      • bb-filter-summary-item-on-click(Optional.) Specifies a function to be called when users click a summary item.
      • bb-filter-summary-item-is-dismissible(Optional.) Indicates whether to include close icons on summary items. (Default: true)
      • bb-filter-summary-item-on-dismiss(Optional.) Specifies a function to be called when users click the close icons on summary items.

Demo

{{item.label}}
{{item.name}}
{{item.description}}

Markup

<div ng-controller="FilterTestController as filterCtrl">
    <div style="padding: 5px;">
        <bb-filter-button 
            bb-filter-button-on-click="filterCtrl.filterButtonClicked()">
        </bb-filter-button>
    </div>
    <bb-filter-summary ng-show="filterCtrl.appliedFilters && filterCtrl.appliedFilters.length > 0">
        <bb-filter-summary-item 
            ng-repeat="item in filterCtrl.appliedFilters" 
            bb-filter-summary-item-on-click="filterCtrl.filterButtonClicked()"
            bb-filter-summary-item-on-dismiss="filterCtrl.onDismiss($index)" >
            {{item.label}}
        </bb-filter-summary-item>
    </bb-filter-summary>

    <div>
        <bb-repeater bb-repeater-expand-mode="none">
            <bb-repeater-item ng-repeat="item in filterCtrl.filteredItems">
            <bb-repeater-item-title>
                {{item.name}}
            </bb-repeater-item-title>
            <bb-repeater-item-content>
                <div>
                {{item.description}}
                </div>
            </bb-repeater-item-content>
            </bb-repeater-item>
        </bb-repeater>
      </div>
</div>
<script type="text/ng-template" id="demo/filter/filters.html">
    <bb-modal>
        <div class="modal-form">
            <bb-modal-header>Food preferences</bb-modal-header>
            <div bb-modal-body>
                <form>
                    <label for="bb-select-type">Fruit type</label>
                    <select id="bb-select-type" ng-model="modalCtrl.filters.fruitType" class="form-control">
                        <option value="any">Any fruit</option>
                        <option value="citrus">Citrus</option>
                        <option value="berry">Berry</option>
                    </select>
                    <label style="margin-top: 15px;">
                        <input type="checkbox" bb-check ng-model="modalCtrl.filters.hideOrange" />
                        Hide orange fruits
                    </label>
                </form>
            </div>
            <bb-filter-modal-footer
                bb-filter-modal-apply="modalCtrl.applyFilters()"
                bb-filter-modal-clear="modalCtrl.clearAllFilters()">
            </bb-filter-modal-footer>
        </div>
    </bb-modal>
</script>

JavaScript

/*global angular */
(function () {
    'use strict';

    function FilterModalController($uibModalInstance, existingFilters) {
        var self = this;

        function clearAllFilters() {
            self.filters = {
                fruitType: 'any'
            };
        }
        
        function transformFiltersToArray(filters) {
            var result = [];

            if (filters.fruitType && filters.fruitType !== 'any') {
                result.push({name: 'fruitType', value: filters.fruitType, label: filters.fruitType});
            }

            if (filters.hideOrange) {
                result.push({name: 'hideOrange', value: true, label: 'hide orange fruits'});
            }

            return result;
        }

        function transformArrayToFilters(array) {
            var i,
                filters = {};

            for (i = 0; i < array.length; i++) {
                if (array[i].name === 'fruitType') {
                    filters.fruitType = array[i].value;
                }

                if (array[i].name === 'hideOrange') {
                    filters.hideOrange = array[i].value;
                }
            }

            return filters;
        }

        function applyFilters() {
            var result = transformFiltersToArray(self.filters);
            $uibModalInstance.close(result);
        }


        if (!existingFilters) {
            clearAllFilters();
        } else {
            self.filters = transformArrayToFilters(existingFilters);
        }

        if (angular.isUndefined(self.filters.fruitType)) {
            self.filters.fruitType = 'any';
        }

        self.clearAllFilters = clearAllFilters;
        self.applyFilters = applyFilters;

    }

    FilterModalController.$inject = ['$uibModalInstance', 'existingFilters'];
    
    function FilterTestController(bbModal) {
        var self = this,
            items = [
                {
                    name: 'Orange',
                    description: 'A round, orange fruit.',
                    type: 'citrus',
                    color: 'orange'
                },
                {
                    name: 'Mango',
                    description: 'Delicious in smoothies, but don\'t eat the skin.',
                    type: 'other',
                    color: 'orange'
                },
                {
                    name: 'Lime',
                    description: 'A sour, green fruit used in many drinks.',
                    type: 'citrus',
                    color: 'green'
                },
                {
                    name: 'Strawberry',
                    description: 'A red fruit that goes well with shortcake.',
                    type: 'berry',
                    color: 'red'
                },
                {
                    name: 'Blueberry',
                    description: 'A small, blue fruit often found in muffins.',
                    type: 'berry',
                    color: 'blue'
                }
            
            ];

        function orangeFilterFailed(filter, item) {
            return filter.name === 'hideOrange' && filter.value && item.color === 'orange';
        }

        function fruitTypeFilterFailed(filter, item) {
            return filter.name === 'fruitType' && filter.value !== 'any' && filter.value !== item.type;
        }

        function itemIsShown(filters, item) {
            var passesFilter = true,
                j;

            for (j = 0; j < filters.length; j++) {
                if (orangeFilterFailed(filters[j], item)) {
                    passesFilter = false
                } else if (fruitTypeFilterFailed(filters[j], item)) {
                    passesFilter = false
                }
            }

            return passesFilter;
        }

        function filterItems(items, filters) {
            var i,
                passesFilter,
                result = [];

            for (i = 0; i < items.length; i++) {
                passesFilter = itemIsShown(filters, items[i]);
                if (passesFilter) {
                    result.push(items[i]);
                }
            }

            return result;
        }

        self.filteredItems = items;

        self.filterButtonClicked = function () {
            bbModal
                .open({
                    controller: 'FilterModalController as modalCtrl',
                    templateUrl: 'demo/filter/filters.html',
                    resolve: {
                        existingFilters: function () {
                            return angular.copy(self.appliedFilters);
                        }
                    }
                })
                .result
                .then(function (result) {

                    self.appliedFilters = angular.copy(result);

                    self.filteredItems = filterItems(items, self.appliedFilters);

                },
                    angular.noop
                );
        };

        self.onDismiss = function (index) {
            self.appliedFilters.splice(index, 1);
            self.filteredItems = filterItems(items, self.appliedFilters);
        }
       
    }

    FilterTestController.$inject = ['bbModal'];
    
    angular
        .module('stache')
        .controller('FilterTestController', FilterTestController)
        .controller('FilterModalController', FilterModalController);
})();