I have successfully integrated Jquery-Autocomplete into my rails app, currently users can search more than 5000+ airports and so far the integration works exactly as desired, however...
Any Airport has multiple columns, currently i am returning the airport name but would like to instead show
**
airport_name - airport_city - airport_iata - airport_icao
**
I have so far used Ryan Bates Railscast to get me started
Episode #102
But amended and tweaked thanks to other resources since his video. Sorry i can't reference them right now but will update my question once i've found links to their instructions.
Either way Autocomplete does work as designed and i have managed to populate a hidden field but i would really like to display more than just the Airport name when searching. I will continue to only save the airport ID.
Any help is appreciated, here is my code.
_form.html.erb
<div class="field">
<%= f.label :departure_airport %><br>
<%= text_field_tag nil, nil, :id => 'claim_departure_airport_name', data: {autocomplete_source: Airport.order(:name).map { |t| { :label => t.name, :value => t.id } } }, class: "form-control" %>
</div>
<%= f.hidden_field :d_airport_id, id: 'd_airport_id' %>
<%= f.hidden_field :a_airport_id, id: 'a_airport_id' %>
claims.coffee
jQuery ->
$('#claim_departure_airport_name').autocomplete
source: $('#claim_departure_airport_name').data('autocomplete-source')
select: (event, ui) ->
# necessary to prevent autocomplete from filling in
# with the value instead of the label
event.preventDefault()
$(this).val ui.item.label
$('#d_airport_id').val ui.item.value
$('#claim_arrival_airport_name').autocomplete
source: $('#claim_arrival_airport_name').data('autocomplete-source')
select: (event, ui) ->
# necessary to prevent autocomplete from filling in
# with the value instead of the label
event.preventDefault()
$(this).val ui.item.label
$('#a_airport_id').val ui.item.value
As you can see i am directly reaching the model data without the need for a dedicated controller although i realise this would be much more intelligent than my current solution as i wish to roll this out in other areas of the platform.
I don't fully understand everything that is happening in the jquery code in my coffee file this was obtained from another source although i forget who to give credit. As far as i know it's taking the ID of the airport and populating the hidden field?
If you can spot how to show other airport database columns to the user that would be great.
Thanks
edit
Also wish to restrict autocomplete from loading the data source into html due to seriously long page load times. A screen shot of what i mean is below.
screenshot of data loading
You can modify the autocomplete source to
<%= text_field_tag nil, nil, id: 'claim_departure_airport_name', data: { autocomplete_source: Airport.select(:id, :name, :city, :iata, :icao).order(:name).map { |t| { label: "#{t.name}-#{t.city}-#{t.iata}-#{t.icao}", value: t.id } } }, class: "form-control" %>
To refactor this a bit, you can move the active record query into a helper
def airport_autocomplete_data
Airport.select(:id, :name, :city, :iata, :icao).order(:name).map { |t| { label: "#{t.name}-#{t.city}-#{t.iata}-#{t.icao}", value: t.id } }
end
and your text field becomes
<%= text_field_tag nil, nil, id: 'claim_departure_airport_name', data: { autocomplete_source: airport_autocomplete_data }, class: "form-control" %>
The main point is here data: {autocomplete_source: Airport.order(:name).map { |t| { :label => t.name, :value => t.id } } }
It builds an array of objects, like [{'label': 'BKK', value: 1}, {'label': 'HAM', value: 2}]
So you either need to add something to the label key, or maybe add a different key and use it later in the select callback.
If you are using rails4-autocomlete Gem. You can easily override from controller.
def autocomplete_profile
term = params[:term]
profiles = Profile.where(
'LOWER(profiles.first_name) LIKE ? OR LOWER(profiles.last_name) LIKE ?',
"%#{term}%", "%#{term}%"
).order(:id).all
render :json => profiles.map { |profile| {:id => profile.id, :label => profile.id, :value => profile.id} }
end
Related
I have just started learning rails, html and javascript. I am using a collection_select to allow a user to select other users in the database:
<%= f.collection_select :id, Customer.where(business_id: current_customer.business_id), :id, :full_name, :prompt => 'Select', :html => { :id => "colleageselect", :onChange => "renderColCal(this)"} %>
<div id = colleaguecal> </div>
I have just been trying to test whether onChange works, by using the javascript:
<script type = "text/javascript">
function renderColCal(select){
alert('this is a test' + select.valueOf() );
document.getElementById("colleaguecal").innerHTML = "foo"
}
</script>
But changing the collection_select value when running the page doesn't do anything? Am I missing something here?
check the generated html if it is what you are expecting. I don't see any issues with the js although it would be better if it was unobstrusive. The only thing that may have caused your issue is that you didn't just passed a hash to the html options. Try
f.collection_select :id,
Customer.where(business_id: current_customer.business_id),
:id,
:full_name,
{ prompt: 'Select' },
{ id: "colleageselect", onChange: "renderColCal(this)" }
I have a rails 4 app with simple form and bootstrap.
I want to ask a question in my form which asks whether users need survey responses. If the answer to that is true, then I want to ask a follow up question. My two survey questions are:
<%= f.input :survey, :as => :boolean, :label => false, inline_label: 'Do you need survey responses?' %>
<br><br>
<%= f.input :survey_link, label: 'Where is your survey?', :label_html => { :class => 'question-data' }, placeholder: 'Include a link to your survey', :input_html => {:style=> 'width: 650px; margin-top: 20px', class: 'response-project'} %>
Is JS if statement the best way to approach this task? I want to hide the second question until the user answers true to the first question.
If so, I'm having trouble understanding how to make this JS work.
I have tried:
if (:survey is :true) {
:survey_link;
}
I can't find any resources to help explain how to do this. Help would be very much appreciated. Thank you.
Obviously the code below depends on what the name of your survey and survey_link inputs look like in actual HTML. So if in this example it is for #user:
<% simple_form_for #user do |f| %>
<%= f.input :survey, :as => :boolean, :label => false, inline_label: 'Do you need survey responses?' %>
<%= f.input :survey_link, label: 'Where is your survey?', :label_html => { :class => 'question-data' }, placeholder: 'Include a link to your survey', :input_html => {:style=> 'width: 650px; margin-top: 20px', class: 'response-project'} %>
<% end %>
Then the JQuery should look like (note the user part - you may have to change this):
<script>
$(function() {
// Hide the survey_link input
$('input[name="user[survey_link]"]').hide();
$('input[name="user[survey_link]"]').closest("label").hide();
// When the survey checkbox changes
$('input[name="user[survey]"]').change(function() {
$('input[name="user[survey_link]"]').closest("label").toggle(this.checked);
$('input[name="user[survey_link]"]').toggle(this.checked);
});
});
</script>
Environment Ruby 2.0.0, Rails 4.0.3, Windows 8.1, jQuery
EDIT: Just FYI, I was discussing the issue the other day and I was told that the common method to solve this problem would be just to pass the record ID. Certainly, I would recommend that solution in a general case. In this case, the record is being created and has not yet been stored, so it has no ID and cannot have one until all required fields are completed.
I need to pass the object instance from the view through jQuery to the controller so that the controller use it to render a partial using dependent selects. This process was generally working even though I was just passing a string that named the object. But, now I have to implement strong parameters to permit updates and that requires the actual instance and not just the string name of the instance.
In jQuery, I use the following to obtain the instance but it is obviously wrong because it only gets me the string name of the instance. I assume it needs to be serialized perhaps? But, I can only get the string name which cannot be serialized.
var car = $('select#car_year_id').attr("car");
The basic question is, how do I retrieve the actual instance of car within jQuery? Alternatively, I guess, the question would be that, given the string name of an instance within Ruby on Rails, how do I address the actual instance? Either one would probably suffice. Of course, other alternatives will be welcomed. Thanks.
The form is:
<div class="span8">
<%= simple_form_for #car,
defaults: {label: false},
html: {class: 'form-vertical'},
wrapper: :vertical_form,
wrapper_mappings: {
check_boxes: :vertical_radio_and_checkboxes,
radio_buttons: :vertical_radio_and_checkboxes,
file: :vertical_file_input,
boolean: :vertical_boolean
} do |f| %>
<%= f.input(:stock_number, {input_html: {form: 'new_car', car: #car}, autocomplete: :off, placeholder: 'Stock number?'}) %>
<%= f.input(:year_id, {input_html: {form: 'new_car', car: #car}, collection: Year.all.collect { |c| [c.year, c.id] }, prompt: "Year?"}) %>
<%= render partial: "makes", locals: {form: 'new_car', car: #car} %>
<%= render partial: "models", locals: {form: 'new_car', car: #car} %>
<input type="submit" form="new_car" value="Create Car" class="btn btn-default btn btn-primary">
<% end %>
</div>
The "makes" partial is:
<%= simple_form_for car,
defaults: {label: false},
remote: true do |f| %>
<% makes ||= "" %>
<% if !makes.blank? %>
<%= f.input :make_id, {input_html: {form: form, car: car}, collection: makes.collect { |s| [s.make, s.id] }, prompt: "Make?"} %>
<% else %>
<%= f.input :make_id, {input_html: {form: form, car: car}, collection: [], prompt: "Make?"} %>
<% end %>
<% end %>
The jQuery is:
$(document).ready(function () {
// when the #year field changes
$("#car_year_id").change(function () {
// make a GET call and replace the content
var year = $('select#car_year_id :selected').val();
if (year == "") year = "invalid";
var form = $('select#car_year_id').attr("form");
if (form == "") form = "invalid";
var car = $('select#car_year_id').attr("car");
if (car == "") car = "invalid";
$.post('/cars/make_list/',
{
form: form,
year: year,
car: car
},
function (data) {
$("#car_make_id").html(data);
});
return false;
});
});
The controller action is:
def make_list
makes = params[:year].blank? ? "" : Make.where(year_id: params[:year]).order(:make)
render partial: "makes", locals: { car: params[:car], form: params[:form], makes: makes }
end
I found the answer! So excited!
There is a new HTML construct that allows you to using an arbitrary attribute to an HTML element as long as the name is preceded by "data-". For example:
<%= f.input(:year_id, {input_html: {form: 'new_car', data-car: #car}}, collection: Year.all.collect { |c| [c.year, c.id] }, prompt: "Year?"}) %>
This is problematic in Rails, because Rails doesn't like hyphens in symbols. However, there is an optional helper using the data: symbol to pass a hash as in:
<%= f.input(:year_id, {input_html: {form: 'new_car', data: { car: #car}}, collection: Year.all.collect { |c| [c.year, c.id] }, prompt: "Year?"}) %>
See: Best way to use html5 data attributes with rails content_tag helper?
Then, within JavaScript, you can use the dataset property to retrieve a DOMStringMap object as follows:
var element = document.getElementById('car_year_id');
var car = element.dataset.car;
See: HTML5 Custom Data Attributes (data-*)
This returns car as a hash object, which is really just what I needed!
Overall reference that helped a lot: Rails 3 Remote Links and Forms: A Definitive Guide
Just for completeness, I used to following code to convert the hash into an object back in the controller:
car_hash = params[:car].gsub!(/":/, '" => ')
null = nil
#car = Car.new(eval(car_hash))
I'm developing autocomplete for a particular form in my rails app; for this purpose I'm using typeahead.js with custom controller method. So far, it works but I need using those values within the form again so that I can press the submit button and the form will be posted and processed by rails normally. How can I do this? Here's the code right now
.page-header
%h1
= #org.name
%small= t('.title')
= form_for #org_admin, |
url: organization_organization_admins_path(#organization) do |f|
.form-group
= f.label t('.user')
= f.hidden_field :user, id: 'user_id'
%input.typeahead{ :type => "text", :autocomplete => "off"}
= f.submit t('.submit'), class: 'btn btn-primary'
= link_to t('.back'), organization_organization_admins_path(#organization)
:javascript
$(document).ready(function() {
$('input.typeahead').typeahead({
name: 'names',
remote: "#{search_organization_organization_admins_path(#organization)}?term=%QUERY",
engine: Hogan,
template: '<p><strong>{{username}}</strong></p>',
limit: 10
}).on('typeahead:selected', function(e, data){
$('#user_id').value = data.id
});
});
So, I would like to populate the :user attribute in the form with the json object returned by the controller
Nevermind, I figured out... the above code is in the right path, except for the call to this line
$('#user_id').value = data.id
Since I'm using jQuery to select the hidden element I had to use the jQuery val function instead
$('#user_id').val(data.id)
I have a two f.select fields in my form with the same object id. I am changing these fields by selecting the parent field using javascript and CSS.
<%= f.label :Service_Phase, 'Service Phase' %>
<%= f.select :Service_Phase, [], { :prompt => 'None' }, class: 'select_phase', disabled: 'disabled' %>
<%= f.select :Service_Phase, (1..52), { :prompt => 'Select Week' }, class: 'select_week' %>
<%= f.select :Service_Phase, (1..12), { :prompt => 'Select Month' }, class: 'select_month' %>
I want to display the select box disabled with the text 'NONE' by default and will change the select_field by the parent select field value. Is it any other neat way to do this in rails? Because when i try to the check the value after selected the value of week in console, its display the empty string. I don't know where am doing wrong and how can I correct this? Thanks in advance.
I think you might be better off just doing that with javascript/jquery. I don't believe rails has a built in way to enable a secondary select field based off the first.