jquerytypeahead.jstypeaheadbloodhound

Typeahead, Bloodhound & Selecting Data Source Issue


I have a script as such:

<script>
        $(document).ready(function() {
            var searchType = $('select[name=searchType]').val();
            var bloodhound = new Bloodhound({
                datumTokenizer: Bloodhound.tokenizers.whitespace,
                queryTokenizer: Bloodhound.tokenizers.whitespace,
                remote: {
                    url: '/'+searchType+'/find?q=%QUERY%',
                    wildcard: '%QUERY%'
                },
            });

            $('#search').typeahead({
                hint: true,
                highlight: true,
                minLength: 3
            }, {
                name: searchType,
                source: bloodhound,
                display: function(data) {
                    return data.name  //Input value to be set when you select a suggestion. 
                },
                templates: {
                    empty: [
                        '<div class="list-group search-results-dropdown"><div class="list-group-item">Nothing found.</div></div>'
                    ],
                    header: [
                        '<div class="list-group search-results-dropdown">'
                    ],
                    suggestion: function(data) {
                        if(searchType == "shipments"){
                            return '<a href="/shipments/i/'+data.UUID+'"><div style="font-weight:normal; margin-top:-10px ! important;" class="list-group-item">' + data.pro_number + ' - Date: '+ data.date +'</div></a></div>'
                        }else if(searchType == "manifests"){
                             return '<a href="/carrier/manifests/view/'+data.id+'"><div style="font-weight:normal; margin-top:-10px ! important;" class="list-group-item">' + data.manifestNumber + ' - Origin: '+ data.terminalOrigin +'</div></a></div>'
                        }else if(searchType == "customers"){
                            return '<a href="/customers/i/'+data.url_string+'"><div style="font-weight:normal; margin-top:-10px ! important;" class="list-group-item">' + data.customer_name +'</div></a></div>'
                        }
                    }
                }
            });                         
        });
    </script>

For the most part, I believe it works. The problem is it sticks to one selection rather than changing selection once one is chosen at any given time.

My search form is rather simple:

<form class="sidebar-form">
        <div class="input-group">
          <input type="text" name="search" class="form-control" placeholder="Search Pro Number" id="search">

          <span class="input-group-btn">
              <button type="submit" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i>
              </button>
            </span>
        </div>
          <select name="searchType" class="form-control">
                <option value="" selected>Search Type</option>
                <option value="shipments">Shipments</option>
                <option value="manifests">Manifests</option>
                <option value="customers">Customers</option>
            </select>
      </form>

As I said, the type ahead and data returns are fine for one, and then I have to reload the page if I wanted to change the dataset it searches. So if I change the dropdown from manifests to shipments, it will still try and search manifests.


Solution

  • Your issue is that Bloodhound assumes that the search URL only changes in the spot where the "query" parameter is. For most cases, this assumption is right, so they made it the default.

    In your case, the URL should changes in two places, though, so the default behavior of Bloodhound isn't good enough.

    It's easy to override the default behavior by supplying a prepare function, which can make more extensive changes to Bloodhound's settings prior to the request.

    The current query and settings are being passed as arguments. All you need to do is to modify the settings.url:

    var bloodhound = new Bloodhound({
        datumTokenizer: Bloodhound.tokenizers.whitespace,
        queryTokenizer: Bloodhound.tokenizers.whitespace,
        remote: {
            url: 'required, but will be overridden in prepare() anyway',
            prepare: function (query, settings) {
                var searchType = $('select[name=searchType]').val();
    
                settings.url = '/' + searchType + '/find?' + $.param({
                    q: query
                });
    
                return settings;
            }
        }
    });
    

    The other approach would be to use N different bloodhound instances, one for every possible searchType value, but each with a fixed URL, and then to dynamically decide in the typeahead configuration which of them to use.