3
\$\begingroup\$

In this code, I'm overriding the sorter and matcher for Twitter-Bootstrap's Typeahead functionality. The reason for the override is to allow state (technically Jurisdiction) abbreviations to be used to match the full state name. I've reduced the length of the source array in this example for brevity, but a full version is available on this fiddle. I also decided to make it so that duplicate entries could not be made.

I went out of my way to make JSHint like my code, but I'd basically like any suggestions. This is my first time doing something like this and I'm relatively new with Javascript anyway. The only things I'm not interested in is white space as I simply formatted this based upon JSFiddle's TidyUp function, the css (as I didn't create it), and suggestions to override highlighter as I don't see the need.

Note: In production the number of inputs is dynamic, which is why I am selecting them each time.

If you need to view the Typeahead source code to understand my overrides, you can download it here

HTML for Example

<input class="jurisdiction">
<br/>
<input class="jurisdiction">
<br/>
<input class="jurisdiction" value="Alberta">

Javascript

var myTypeAhead = ! function ($) { // To make JSHint happy
        var states = [{            //shortened for brevity
            name: 'Alabama',
            abbreviation: 'AL'
        }, {
            name: 'Alberta',
            abbreviation: 'AB'
        }],
            stateNames = [],
            overrides = {
                matcher: matcherOverride,
                sorter: sorterOverride
            },
            usedStateNames = getUsedStateNames();
        //Populate stateNames
        $.each(states, function () {
            stateNames.push(this.name);
        });

        function getState(stateName) {
            return $.grep(states, function (e) {
                return e.name === stateName;
            })[0];
        }

        function matcherOverride(item) {
            var state = getState(item);
            var query = this.query.toLowerCase();
            // true if entered value contained in state name or abbreviation
            return ~state.name.toLowerCase().indexOf(query) ||
                   ~state.abbreviation.toLowerCase().indexOf(query);
        }

        function sorterOverride(items) {
            //Orders state names based upon match type
            var beginswith = [],
                caseSensitive = [],
                caseInsensitive = [],
                abbreviationMatch = [],
                item = items.shift(),
                state,
                lcQuery = this.query.toLowerCase();
            while (item) {
                state = getState(item);
                if (state && !state.abbreviation.toLowerCase().indexOf(lcQuery)) {
                    abbreviationMatch.push(state.name);
                } else if (!item.toLowerCase().indexOf(lcQuery)) {
                    beginswith.push(item);
                } else if (~item.indexOf(this.query)) {
                    caseSensitive.push(item);
                } else {
                    caseInsensitive.push(item);
                }
                item = items.shift();
            }
             return abbreviationMatch.concat(beginswith, caseSensitive, caseInsensitive);
        }    

        function UpdateDataSource(e) {
            //$(e).typeahead(overrides).data('typeahead').source = getDataSourceArray();
            $(e).typeahead(overrides).data('typeahead').source = getDataSourceArray(e.value);
        }

        function getDataSourceArray(currentValue) {

            usedStateNames = removeArray(usedStateNames, [currentValue]);
            return removeArray(stateNames, usedStateNames);
        }

        function removeArray(original, toRemove) {
            return $.grep(original, function (a) {
                return !~$.inArray(a, toRemove);
            });
        }

        function getUsedStateNames() {
            var usedStateNames = [];
            $('.jurisdiction').each(function () {
                usedStateNames.push(this.value);
            });
            return usedStateNames;
        }
        $(document).on("focus", ".jurisdiction", function () {
            UpdateDataSource(this);
        });
        $(document).on("change", ".jurisdiction", function () {
            //Disallow repeats or unlisted values
            if (!~stateNames.indexOf(this.value) || ~usedStateNames.indexOf(this.value)) {
                this.value = "";
            }
        });
        $(document).on("blur", ".jurisdiction", function () {
            usedStateNames.push(this.value);
        });
    }(window.jQuery);
\$\endgroup\$
  • \$\begingroup\$ which bootstrap version are you using ? \$\endgroup\$ – Muhammed Mar 12 '14 at 12:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.