gmaps4rails and autocomplete google place API incompatibility - ruby-on-rails

I've a problem of compatibility between gmaps4rails gem and google place API
Basically if I put in my view a gmpas4rails like this:
<%=gmaps%>
then this script doesnt work anymore (it normaly activate an autocomplete on user_address field:
$(document).ready(initialize_gmaps_autocomplete_user_address());
function initialize_gmaps_autocomplete_user_address() {
var input = document.getElementById('user_address');
var defaultBounds = new google.maps.LatLngBounds(new google.maps.LatLng(42.71422,-4.222666), new google.maps.LatLng(51.179343,8.47412));
var autocomplete = new google.maps.places.Autocomplete(input);
autocomplete.setBounds(defaultBounds);
autocomplete.setTypes(['geocode']);
}
I've tried to call the script by gmaps4rails.call_back and to change the var names in my scripts...
Any idea?

I guess you make a second call to the google api which mess things up.
Two solutions here:
1) don't include the js from the partial:
<%= gmaps({your_hash}, true, false) %>
And include all the js files manually but be sure to write:
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false&libraries=geometry,places"></script>
Here is the original partial so you don't forget any file.
2) Grab the current version on git and add places directly:
<%= gmaps({ "map_options" => { "libraries" => ["places"] } }) %>
I'll update the gem later, so versions above 0.10.2 will have this included.

Actually 2) should be
<%= gmaps({:map_options => {:libraries => ["places"]}}) %>
because in the source code of gmaps4rails symbols are used instead of strings.
To make it work with strings you'd have to use HashWithIndifferentAccess:
<%= gmaps(HashWithIndifferentAccess.new("map_options" => {"libraries" => ['places']}))%>

Related

How get the value of a collection_select within the same html.erb form itself

I have a form with this collection_select
<%= collection_select :bmp, :bmpsublist_id,
Bmpsublist.where(:bmplist_id => #bmp.bmp_id), :id,
:name,{ :required => false,
:selected => #bmp.bmpsublist_id, } %>
I would like to be able to get the value of this collection_select so that lower down in the same form, I can check to see which list I should use when displaying another collection_select
Something like this partial pseudocode here:
if earlier result == 2 then
use this list: Irrigation.where(:id != 8)
else
use this other list: Irrigation.all
and they would be updating the collection_select:
<%= collection_select :bmp, :irrigation_id, the_chosen_list_from_above, :id, :name,
{:prompt => 'Select Irrigation Type'}, {:required => true} %>
How can I do that?
Based on what you've asked, there are two ways to query and apply the value of the collection: static and dynamic.
Static occurs at the time that the ERB view is rendered, and this will apply the logic at the time that the page is initially rendered and loaded. Dynamic occurs after the page is loaded, and as the user interacts with the elements on the page. Which approach you choose to go with depends entirely on your application's design and intended level of interaction with the user.
Static Detection
You're already specifying the selected item in the initial collection_select, so you can reuse that in your later code. Try this, based on your pseudocode example:
<% if #bmp.bmpsublist_id == 2 %>
<% irrigation_list = ["Sprinkle", "Furrow/Flood", "Drip", "Furrow Diking"] %>
<% else %>
<% irrigation_list = ["Sprinkle", "Furrow/Flood", "Drip", "Furrow Diking", "Pads and Pipes - Tailwater Irrigation"] %>
<% end %>
<%= select :bmp, :irrigation_id, options_for_select(irrigation_list),
{ :prompt => 'Select Irrigation Type'}, { :required => true } %>
Why will this work? The :selected option for the initial collection_select is where you provide which option will be initially chosen. Since this value is typically taken from the model value, it's supplied in a separate param from the actual collection values. So, it's queued up and ready for you, simply by virtue of sticking to the Rails conventions.
The subsequent select builds the HTML <select> element and uses the options_for_select to turn the array of options into HTML <option> elements. This way, you can use the variable list of options to select from, based on which element from the original collection_select was chosen.
Best thing of all: with the static approach, you don't have to drop into Javascript (or jQuery) to do this; it gets rendered directly by the ERB template (or the HAML template, if that's your bag).
Dynamic Detection
If you actually wanted dynamic behavior, you can drop into Javascript / jQuery and get it done. You can create your "Irrigation Types" select just like with the static approach (above), except that you initialize it with all of the options, like this:
<%= select :bmp, :irrigation_id,
options_for_select(["Sprinkle", "Furrow/Flood", "Drip", "Furrow Diking", "Pads and Pipes - Tailwater Irrigation"]),
{ :prompt => 'Select Irrigation Type'}, { :required => true } %>
Then, edit the Javascript source associated with your view (let's call it Product). Open the app/assets/javascripts/product.js (if you use CoffeeScript, it's the product.coffee file in the same directory).
Edit that Javascript file to include this code:
function OnProductEditForm() {
// Edit the selectors to match the actual generated "id" for the collections
var bmp_collection = $("#product_bmp");
var drip_collection = $("#product_irrigation_type");
var drip_option = drip_collection.find("option")[2];
function select_available_drip_options() {
var value = bmp_collection.val();
if (value == 2) {
drip_option.attr("disabled", "disabled");
} else {
drip_option.removeAttr("disabled");
}
}
bmp_collection.change(function() {
select_available_drip_options();
});
select_available_drip_options();
}
This identifies the HTML element of the collection and installs a change event handler. You'll need to verify the collection element's id, as per the code comment, and the rest happens from there. When the collection is changed (a new value is chosen), the event handler will hide or show the third select <option> (specified as find("option")[2]), as appropriate for the #product_bmp selection.
Next, in the app/views/products/_form.html.erb, include this at the end of the file:
<script>
jQuery(document).ready(OnProductEditForm);
// Uncomment the next 2 lines for TurboLinks page refreshing
//jQuery(document).on('page:load', OnProductEditForm);
//jQuery(document).on('page:restore', OnProductEditForm);
</script>
This will automatically load the OnProductEditForm method when the page loads, and will result in the afore-mentioned event handler getting installed. Note that the last 2 lines are necessary if you have TurboLinks enabled, as TurboLinks initiates events for page loading independently of the standard $(document).ready.
And that's all there is to it. Adding dynamic behavior is just that easy!
You're gonna have to use some javascript (jquery and ajax, I would suggest). When the value of the first select change (jquery), it requests (ajax) the collection (passing the current value selected) to a controller action that returns the collection that should be used. With the collection returned, you populate the options (jquery) for the second select. It's not quite simple, but if you ever did something like that, you shouldn't have problems. If never did, do some research about it... it's quite useful and improve user experience a lot!

simple_form select collection populated by AJAX

I thought this would be fairly easy, but I'm not finding any help by Googling.
I have a form (simple_form) with numerous inputs with select lists (collections) that are populated from the database, so many it is slowing down the initial page load. I thought I could speed it up by only populating those drop down lists as the user selects them using Ajax. Is there something built in like remote => true for the form itself? Can someone point me in the right direction?
EDIT:
I found this SO question but I cannot figure out how to implement the answer.
Currently, my form looks like this;
= simple_form_for(#account)
= f.input :account_number
= f.input :area, collection: #areas
= f.submit nil, :class => 'btn btn-primary'
Based on the answer in the linked question, I should add something like this, but of course it is not working
= simple_form_for(#account)
= f.input :account_number
= f.input :area, collection: #areas, :input_html => {"data-remote" => true, "data-url" => "/my_areas", "data-type" => :json}
= f.submit nil, :class => 'btn btn-primary'
I can think of two ways to go about this if you don't want to load the contents initially when the page loads. One way is to run a script after the DOM has loaded to change the options for the select tag and the other is to collect the options when you click on the drop-down on the select element. I might go for the first way because there wouldn't be latency when a user clicks on the select element--they wouldn't have to wait for the options to populate.
So you'd run a jQuery script on document ready that makes an AJAX call to a method in your controller, which then returns the collections you want, then you iterate through the select elements you want to change with JQuery scripts. It might look something like this.
# in view with the select options to be changed
$(document).ready(function() {
$.get(change_selects_path, function(response) {
$.each(response, function(args) {
// code for each select element to be changed
$('.class_of_select_element').html(<%= j options_from_collection_for_select(args) %>);
});
});
)};
# in controller
def change_selects
# make db calls and store in variables to feed to $.get request
end
Note that this not tested but should give you a good start towards a solution. For further info on the each loop, you can check out this documentation.
Not sure if this fits your exact use case (please clarify if not), but I also have a few collection selects that have a large amount of database rows behind them. I use the select2-rails gem to take care of this. Users can begin to type in the name and the relevant results will show up (it will also show a few initially if they don't type something).
Check it out here: https://github.com/argerim/select2-rails
Edit: For a cascading dropdown, I recommend this gem: https://github.com/ryanb/nested_form

Bootstrap Typeahead in Rails

I'm using Bootstrap-sass and formtastic in my Rails application, and I'm not sure why the bootstrap-typeahead feature isn't working.
Form partial:
<%= f.input :tag, :input_html => { :'data-provide' => "typeahead", :'data-source' => '["hello", "hellow", "heaven", "helo", "herr"]' } %>
application.js manifest:
//= require bootstrap-typeahead //typeahead is correctly loaded, checked with firebug
result HTML source code:
<input :data-minLength="2" data-provide="typeahead" data-source="["hello", "hellow", "heaven", "helo", "herr"]"
In the end, I will need to customize typeahead to get the performance I want, but even this simple javascript isn't working for some reason. I cant find anything wrong with the code. Could anyone help me?
UPDATE:
I tried it in the javascript way as follows:
<script> //call typeahead
$(function() {
$('input#type_ahead').typeahead({
'source' : ["hello", "heaven", "heythere"]
});
})
</script>
<%= f.input :tag_list, :input_html => { :id => "type_ahead" }, %> //input tag
And still it seems like typeahead fails to work. i.e) typing in "he" does not get me a dropdown of those three items in the above array. Does anyone have an idea?
I think you need to set html_safe for:
{ :'data-source' => '["hello", "hellow", "heaven", "helo", "herr"]'.html_safe }
Have you called the typeahead() method when your page loads? You need to do something like this;
$(function() {
$('input').typeahead();
})
You'll need to assign a class or id to your input to bind the typeahead to it specifically (Rails probably has assigned an id to it automatically, I'm presuming you've omitted it specifically)
$(function() {
$('input#my-tag-field-with-a-cool-typeahead').typeahead();
})
edit:
The following worked for me. It'll take a bit of modification to the rails part to fit your situation, but this definitely works.
<script>
$(function() {
$('input#type_ahead').typeahead()
}
</script>
<%= text_field_tag :test_type, '', data: {provide: 'typeahead', source: "['hello','heythere','heaven']"} %>

Why is a data hash returning a compile error in Rails 3.1 and 3.2 app?

I am messing around with Railscast #102 Auto-Complete Association in a Rails 3.1 app, which I've just upgraded to 3.2.
When I try to add the data hash to a text field
<%= f.text_field :category_name, data: {autocomplete_source: Category.order(:name).map(&:name)} %>
Rails generates a compile error, indicating there is a problem with the data hash.
So I rewrote the hash to
<%= f.text_field :category_name, 'data-autocomplete_source' => Category.order(:name).map(&:name)} %>
This is working, but can someone explain to me if there are any differences between these two approaches that I should be aware off.
Secondly, if I set up the autocomplete function with a static hash of values
$(function() {
$('#post_category_name').autocomplete({
source: ['foo', 'food', 'four']
});
});
The autocomplete works. But if I use the data hash:
$(function() {
$('#post_category_name').autocomplete({
source: $('#post_category_name').data('autocomplete_source')
});
});
autocomplete is not working? In the console it returns
GET http://app.dev/post/4/foo%20food%20four?term=foo 404 (Not Found)
This is confusing me, as there are clearly related terms in the GET request. Is this due to my adjusting the data hash, or is something else going on here?
Thanks for your ideas or suggestions to help me learn how all this works.
The symbol: value JavaScript-ish Hash syntax is new in 1.9 so that explains your first problem. Switching to a 1.9 Ruby or using the traditional syntax:
<%= f.text_field :category_name, :data => { :autocomplete_source => Category.order(:name).map(&:name) } %>
should take care of that.
Check the generated HTML, I think the data attribute will be data-autocomplete-source rather than data-autocomplete_source so try this:
$('#post_category_name').autocomplete({
source: $('#post_category_name').data('autocomplete-source')
});

RoR live-search (text_field_with_auto_complete) submit

I have a "Movies" and a "Actors" table and "Casts" as join-model. To be more specific "Casts" has movie_id, actor_id and rolename.
I want in "Movies" form to add a live search to search through actors and a "rolename" text_field and save those to "Casts".
I don't know if text_field_with_auto_complete is the right choice but i prefer not to use much javascript because i am not familiar with it.
I've been searching all over the internet to find something similar to this without any result.
I've manage to get it working with "#actors.each do" but it makes a very long list.
It's not a plugin, but with a little jQuery magic, you can make use of http://github.com/chadisfaction/jQuery-Tokenizing-Autocomplete-Plugin. The nice thing about this is that since it is pure JS in its implementation, you can create the AJAX call yourself in Rails and only display what you want. It even allows you to add a stylesheet to the dropdown if you want to make it more Facebook like. In your controller, add a function so the AJAX call will return a list of rows in JSON:
def taglist
tags = []
sql = "SELECT id,name ... LIMIT 15" # Enter SQL here to produce a possible result set
result = ActiveRecord::Base.connection.execute(sql)
# Iterate over the hash values and push them into an array
result.each { |field| tags.push( {"id" => field[0], "name" => field[1]} ) }
result.free
render :json => tags, :layout => false
end
In the view, add the following code:
<%= javascript_include_tag 'jquery.tokeninput' %>
<%= stylesheet_link_tag 'token-input-facebook' %>
<script type="text/javascript">
jQuery(document).ready(function () {
jQuery("#actors_role").tokenInput("/actors/rolesearch", {
allowNewValues: false,
canCreate: false,
hintText: "Enter the actor's name or role they played",
});
});
</script>
See text_field_with_auto_complete inside form_for
In the auto_complete controller action, make sure your SQL query is restricting the actors names using the passed param.

Resources