AngularJS: Simple Custom Filter

by Jack

HTML

<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js"></script>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/css/bootstrap-combined.min.css">
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular-resource.js"></script>
<div id="liveFilter">
    <div class="liveFilterContainer">
        <input type="text" class="liveFilterInput default" value="Live Filter" />	<a href="#" class="clearField" title="Clear Filter">x</a>

    </div>
    <div class="noResults"><strong>Sorry.</strong> There is no match for your filter; please try again.</div>
    <table class="liveFilterList" border="0">
        <tbody>
            <tr>
                <th>Post</th>
                <th>Ambassador</th>
                <th>Gender</th>
                <th>Born</th>
                <th>Cone</th>
                <th>Year In</th>
                <th>2nd+?</th>
                <th>Nominated</th>
            </tr>
            <tr>
                <td>Afghanistan</td>
                <td>P. Michael McKinley</td>
                <td>Male</td>
                <td>1957</td>
                <td>Blank</td>
                <td>1982</td>
                <td>Yes</td>
                <td>2007</td>
            </tr>
            <tr>
                <td>Albania</td>
                <td>Donald Lu</td>
                <td>Male</td>
                <td>1966</td>
                <td>Political</td>
                <td>1990</td>
                <td>No</td>
                <td>2014</td>
            </tr>
            <tr>
                <td>Algeria</td>
                <td>Joan Polaschik</td>
                <td>Female</td>
                <td>Blank</td>
                <td>Political</td>
                <td>1995</td>
                <td>No</td>
                <td>2014</td>
            </tr>
            <tr>
                <td>Angola</td>
              ...

CSS

#liveFilter {
    width: 680px;
    border-radius: 5px;
    -moz-border-radius: 5px;
    background: #fff;
    font: normal 10px Verdana, Arial, Helvetica, sans-serif;
}
#liveFilter .liveFilterContainer {
    border: solid 1px #ccc;
    padding: 6px;
    background: #f5f5f5;
}
#liveFilter .liveFilterContainer .liveFilterInput {
    border: solid 1px #ccc;
    padding: 4px 30px 4px 4px;
    font-size: 16px;
    color: #666;
}
#liveFilter .liveFilterContainer .liveFilterInput.default {
    color: #ccc;
    font-style: italic;
}
#liveFilter .liveFilterContainer .clearField {
    background: #80bce8;
    width: 16px;
    padding: 0 6px 3px 6px;
    color: #fff;
    text-decoration: none;
    line-height: 0;
    font-weight: bold;
}
#liveFilter .liveFilterList {
    width: 600px;
    border: solid 1px #ccc;
    border-top: 0;
}
#liveFilter .liveFilterList tr th:first-child, #liveFilter .liveFilterList tr td:first-child {
    padding-left: 5px;
}
#liveFilter .liveFilterList tr th {
    text-align: left;
    padding: 3px 3px;
    font-weight: bold;
}
#liveFilter .liveFilterList tr td {
    border-top: solid 1px #eee;
    padding: 3px 3px;
    color: #333;
}
#liveFilter .clearField {
    display: none;
}
#liveFilter .noResults {
    display: none;
    padding: 10px;
    color: #fff;
    background: #982929;
    margin: 2px;
}

JavaScript

jQuery(document).ready(function (e) {

    var columnsToIndex = [1, 2, 3, 4, 5, 6, 7, 8]; // first column is 1

    initLiveFilter(columnsToIndex);
});

// Live Filter
function initLiveFilter(columnsToIndex) {

    var liveFilter = jQuery("#liveFilter");

    if (liveFilter.length > 0) {

        var liveFilterField = liveFilter.find("input.liveFilterInput"),
            liveFilterGrid = liveFilter.find("table.liveFilterList"),
            liveFilterGridRows = liveFilterGrid.find("tr:gt(0)"), // gt(0) prevents the first row (normally a TH) from being included.
            liveFilterClear = liveFilter.find(".clearField"),
            liveFilterNoResults = liveFilterGrid.prev(),
            liveFilterDataArray = new Array(),

            //Create an array and populate it with key codes that should not cause shake effects

            characterValidationArray = [8, 45, 46], //backspace, insert, delete

            //Create an array and populate it with key codes that don't trigger an action

            characterExclusionArray = [13, 20, 27, 33, 34, 37, 39, 35, 36, 16, 17, 18, 144, 145]; // enter, caps, esc, page up, page down, left, right, home, end, shift, ctrl, alt, num lock, scroll lock

        // Create the datasources we'll use to index the content

        if (columnsToIndex.length > 1) {

            for (col = 0; col <= columnsToIndex.length - 1; col++) {

                liveFilterGridRows.children("td:nth-child(" + columnsToIndex[col] + ")").each(function (i) {

                    liveFilterDataArray[liveFilterDataArray.length++] = jQuery(this).text();

                });
            }

        } else {

            liveFilterGridRows.children("td:first-child").each(function (i) {

                liveFilterDataArray[i] = jQuery(this).text();

            });
        }

        // When a key is pressed in the designated input field - do the following:

        liveFilterField.on("keyup", function (key) {

            // Check the character that was...