Typeahead in rails app: Append JSON request to only one specific request instead of appending JSON request to every request via prefetch
Asked Answered
N

2

13

The type ahead functionality works where it is supposed to. The issue though is that the type ahead functionality is making the JSON request on every request for the data when it should really only happen for one specific request.

I have the following controller:

#controllers/agencies_controller.rb
class AgenciesController < ApplicationController

  def get_unique_agency_names
    @unique_agency_names = Agency.uniq.pluck(:name)
    respond_to do |format|
      format.json { render json: @unique_agency_names }
    end
  end
  ...
end

I have the following in my javascript file:

#app/assets/javascripts.agencies/index.js
$(document).ready(function(){
  /* For typeahead functionality on name input of search form for agencies */
  var agency_names = new Bloodhound({
    datumTokenizer: Bloodhound.tokenizers.whitespace,
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    prefetch: '../agencies/get_unique_agency_names.json'
  });

  $('#prefetch .typeahead.name_input').typeahead(null, {
    name: 'agency_names',
    source: agency_names
  });
});

And just for completion, here is the one place where I want this functionality to happen: In this form:

# just showing the relevant part of the form
<div class="form-group" id="prefetch">
  <%= f.label :name_cont, "Agency Name" %>
  <%= f.text_field :name_cont, class: "form-control typeahead name_input", placeholder: "Enter Agency Name" %>
</div>

Here is my relevant route in config/routes.rb

resources :agencies do
  collection do
    get 'get_unique_agency_names'
  end
end

My specific question is: How can I ensure that the GET "/agencies/get_unique_agency_names" is only called when it is supposed to? Right now it is appending this JSON request for every request. I only want the JSON request to happen for one specific request.

Twitter's Type Ahead Examples

Nystatin answered 20/11, 2015 at 19:4 Comment(3)
Isn't it just the prefetch thing? "Prefetched data is fetched and processed on initialization."Harlequin
@DaveNewton I was thinking about that. I'm just not sure what I am supposed to put in its place.Nystatin
Don't prefetch? Only prefetch on pages where it's meaningful? The Bloodhound repo lists the prefetch options you can use. If it's on every request that means this JS is being included even on pages for which it doesn't matter, and the non-absolute URL means it'll be appending the URL to whatever page you're on.Harlequin
R
3

I think you need this

  $('#prefetch .typeahead.name_input').typeahead(null, {
    generateOnLoad:false,
    name: 'agency_names',
    source: agency_names
  });

generateOnLoad {boolean}

null (default)

If enabled, the source data will be generated (doing Ajax request and preparing to data to be searched) on page load instead of waiting for the input to be focused.

PN:This option does not work well with dynamic: true unless some other configuration is adjusted.

Also, If you find the rails manifest file adds your call to every page just check element exists before type ahead is bound:

if($('#prefetch .typeahead.name_input').length){
      $('#prefetch .typeahead.name_input').typeahead(null, {
        generateOnLoad:false,
        name: 'agency_names',
        source: agency_names
      });
}
Rillings answered 24/11, 2015 at 3:13 Comment(0)
M
3

I would suggest a strategy for “limiting” requests, rather than programmatically enforcing a single request, as it seems you are dealing with a large data set. You can set Bloodhound’s prefetch option to cache what you can, and the sufficient and remote options to ensure that requests for your JSON file are back-filled and rate-limited. Set a higher value for Typeahead’s minLength option as a last line of defense.

Prefetch will serve you to a degree, as it depends on the browser’s local storage for caching, which has limited capacity. If your data set is large, it will only cache a portion, and further requests will be required after initialization.

Remote handles requests after initialization, and can debounce or throttle these requests for you, thereby reducing the number of requests made. See the url, rateLimitBy, and rateLimitWait options, which can be assigned to remote as a hash. Further, Bloodhound will use remote to back-fill additional datums if your sufficient datum count is not reached.

Finally, don’t pass null and set the minLength option to something higher than the default of 1 on your Typeahead constructor. This will prevent overly abundant lookups on your dataset. Just be sure that the minLength value is shorter than the length of your smallest, possible result.

Monolingual answered 24/11, 2015 at 18:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.