Google Maps For Rails replaceMarkers not working - ruby-on-rails

Am I missing something obvious? Map keeps loading #oldjson which I set in the controller and won't be replaced when I set it in the view.
View code:
<% #json = Map.find_by_id('39').to_gmaps4rails %>
<%= gmaps("markers" => {"data" => #oldjson, "options" => { "draggable" => true } } ) %>
<script>
Gmaps.map.replaceMarkers(<%= #json %>);
</script>
Thanks.

I guess you"re facing a js error with this current code.
The reason is the following:
the js used and created by gmaps4rails is put within the yield :scripts
so your additionnal js here is called before the map is created
Solution:
<% #json = Map.find_by_id('39').to_gmaps4rails %>
<%= gmaps("markers" => {"data" => #oldjson, "options" => { "draggable" => true } } ) %>
<% content_for :scripts do %>
<script>
Gmaps.map.replaceMarkers(<%= #json %>);
</script>
<% end %>

Related

Using js.erb in rails

In Rails 5 app with devise, I need to use a new.js.erb file to update select tag in my registrations view and controller. I cant seem to figure out why my new.js.erb file isn't working.
I've tried to use respond_to in controller as below,
registrations-controller.rb
def new
super
#cities = CS.get(:us,params[:state])
respond_to do |format|
format.js { render '/new.js.erb' }# layout: false }
format.html
end
end
new.html.erb
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), :remote => true) do |f| %>
<div class="signup-input-container">
<div class="field">
<%= f.text_field :firstname, autofocus: true, autocomplete: "firstname", placeholder: "First name", class: "signup-input-container--input" %>
</div>
<div class="field">
<%= f.select :state, options_for_select(CS.states(:us).map { |code, name| [name, code] }),{:prompt => "State"}, {:class => "signup-input-container--input", :id => "state-picker"} %>
</div>
<div class="field">
<%= f.select :city, options_for_select([]),{}, {:class => "signup-input-container--input", :id => "city-picker"} %>
</div>
</div>
<% end %>
new.js.erb
var city = document.getElementById("city-picker");
while (city.firstChild) city.removeChild(city.firstChild);
var placeholder = document.createElement("option");
placeholder.text = "Choose a city";
placeholder.value = "";
city.appendChild(placeholder);
<% #cities.each do |c| %>
city.options[city.options.length] = new Option('<%= c %>');
<% end %>
main.js
var state = document.getElementById("state-picker");
state.addEventListener("change", function() {
$.ajax({
url: "/states?state=" + state.value,
type: "GET"
})
})
I'm expecting this to create select tag options with my array of cities in my controller. Does anyone know how to get this to work?
To solve this you should just setup a separate controller where you can fetch the data from asynchronously and alternatively there are also several free API's which can be used for geographical lookup such as Googles Geocoding API and Geonames.
To setup a separate controller you can do it by:
# /config/routes.rb
get '/states/:state_id/cities', to: 'cities#index'
# /app/controllers/cities_controller.rb
class CitiesController < ApplicationController
# GET
def index
#cities = CS.get(:us, params[:state_id])
respond_to do |f|
f.json { render json: #cities }
end
end
end
I would skip using a .js.erb template altogether and just return JSON data which you can use directly in your JS or with one of the many existing autocomplete solutions. .js.erb only makes sense for extensive HTML templating (like for example rendering an entire form) where you want to reuse your server side templates - it greatly increases the complexity and generally makes a mess of your javascript which is not worth it just to output a list of option tags.
// If you are using jQuery you might as well setup a delegated
// handler that works with turbolinks,
$(document).on('change', '#state-picker', function(){
$.getJSON("/states/" + $(this).value() + "/cities", function(data){
// using a fragment avoids updating the DOM for every iteration.
var $frag = $('<select>');
$.each(data, function(city){
$frag.append$('<option>' + data + '</option>');
});
$('#city-picker').empty()
.append($('frag').children('option'));
});
});

Extra characters rendered in view that cannot be found! A possible bug in rendering engine?

I am developing an application using rails 3.2.0 and ruby 1.9 on a Mac
I have a very strange error when rendering an index view
Rails is rendering the characters us at the bottom of the screen, below an index table, and I cannot find these characters in the view.
This part of the view looks like
<section id="main">
<section id="group"></section>
<section id="content">
<section id="data_table_section">
<script>
us
</section>
</section>
The part from id=content is yield in a layout file
<section id='content'>
<%= yield %>
</section>
When I delete the content of the view template, i.e the the us is still there
When I delete <%= yield %> in the layout, the us disappears
When I search for the us in the view code it is not found
When I add my own extra characters in the bottom of the view template code, after tags the us is displayed after these characters
When I delete the layout template the us is still there
The only thing I can come up with is that us is generated by the yield function in some mysterious way, but that seems as a very strange explanation!
Anyone that has had this problem before?
Anyone that know how to find extra characters as us in the code ?
Could it be a bug in the rendering engine ?
Any advices would be great appreciated
Here follows my view code. I use tableastic gem and some other gems
<% if !#unit.nil?
header_text="Deltagarlista för #{#unit.class.model_name.human} #{#unit.name}"
else header_text='Deltagarlista för ST-Forum'
end %>
<section id='data_table_section'>
<article id='remote_clinic_article'></article>
<article id="users_article">
<%= table_for(#users) do |t| %>
<thead ><tr ><th id='table_header' colspan=17><%=header_text%></th></tr></thead>
<thead><tr style='text-align:center;' ><th colspan=15><%= render :partial=>'users/filter'%></th></tr></thead>
<% index=(params[:page].to_i-1)*#per_page%>
<%= t.data do
t.cell(:id, :heading => "Id") {|p| index+=1}
t.cell(:portrait, :heading => "Foto") {|p| image_tag(p.portrait_image,:height=>'24px')}
t.cell(:name,:heading => sort_to("Namn",users_url(:sort_field=>'surname', :sort=>#sort),#sort_field)) {|p| link_to(mark_search_hits(p.name,#search),user_path(p.id))}
t.cell(:clinic, :heading => sort_to("Arbetsplats",users_url(:sort_field=>'clinics.name', :sort=>#sort),#sort_field)) {|p| link_to(mark_search_hits(p.clinic.name,#search),clinic_path(p.clinic.id)) unless p.clinic.nil?}
t.cell(:email,:cell_html => {:class => "address"},
:heading => sort_to("Email",users_url(:sort_field=>'email', :sort=>#sort),#sort_field)) {|p| mail_to(mark_search_hits(truncate(p.email,:length =>20),#search))}
t.cell(:user_roles,:cell_html => {:style => "width:50px"},
:heading => sort_to("Roller",users_url(:sort_field=>'user_roles.role_index', :sort=>#sort),#sort_field)) {|p| mark_search_hits(p.roles(true).to_sentence,#search)}
t.cell(:groups, :heading => sort_to("Grupper",users_url(:sort_field=>'groups.name', :sort=>#sort),#sort_field)) {|p| mark_search_hits(to_sentence(p.groups),#search)}
t.cell(:forum, :heading => sort_to("ST-forum",users_url(:sort_field=>'forums.name', :sort=>#sort),#sort_field)) {|p| mark_search_hits(link_to(p.forum.name,clinic_path(p.forum.id)),#search) unless p.forum.nil?}
t.cell(:st_starts_on, :heading => sort_to("ST-start -- slut",users_url(:sort_field=>'employments.st_starts_on', :sort=>#sort),#sort_field)){|p| mark_search_hits(between_user_dates(p.employment.st_starts_on,p.employment.st_end_on),#search) unless p.employment.nil?}
t.cell(:legitimation_on,:heading => sort_to("Legitimation",users_url(:sort_field=>'employments.legitimation_on', :sort=>#sort),#sort_field)){|p| mark_search_hits(to_user_date(p.employment.legitimation_on),#search) unless p.employment.nil?}
t.cell(:employed_on,
:heading => sort_to("ST-kontrakt",users_url(:sort_field=>'employments.employed_on', :sort=>#sort),#sort_field)){|p| mark_search_hits(to_user_date(p.employment.employed_on),#search) unless p.employment.nil?}
t.cell(:last_visit,
:heading => sort_to("Inloggad senast",users_url(:sort_field=>'last_visit_at', :sort=>#sort),#sort_field)){|p| mark_search_hits(to_user_date(p.last_visit_at),#search) }
t.cell(:mail,
:heading => "Handledare / Handledd") {|p| if !p.supervisors.blank? then mail_supervisors(p) elsif !p.supervised.blank? then mail_supervised(p) end}
t.cell(:id, :cell_html => {:style => "width:30px"},:heading=>image_to('new.png',new_user_path,:class=>'no_class')) {|p| (image_to('destroy.png',user_path(p),:class=>'none',:method=>'delete', :id=>'destroy_button', :confirm => "Vill du verkligen radera vald kurs ",:title=>'Radera kurs')+' '+image_to('map.png', map_address_path(p.address.id),:method=>:get,:class=>'none', :remote=>true, :title=>'Visa en karta över bostadsområdet')).html_safe}
end%>
<tfoot>
<tr >
<td colspan="16" class='flickr_pagination'><%= will_paginate #users, :container => true %><span class="table_filter_text">
<% if #count_users==0 %>
<span class="table_filter_alert_text">
<%=" Inga användare tillgänglig för #{put_filter(#filterparams)}".html_safe%>
</span>
<%else%>
<span class="table_footer_text">
<%="Visar användare "+((params[:page].to_i-1)*#per_page+1).to_s+" till "+([(params[:page].to_i-1)*#per_page+#per_page,#count_users].min).to_s+" av #{#count_users.to_s} användare" .html_safe%>
<br/><%= "Med #{ put_filter(#filterparams)}".html_safe %>
</span>
<%end%>
</td>
</tr>
</tfoot>
<% end %>
</article>
</section>
<script>
$(document).ready(function() {
/* $('.pagination a').attr('data-remote', 'true');*/
jQuery(".best_in_place").best_in_place();
});
// Observe forum_field and filter group_options
$(document).ready(function(){
$("#forum_id").live('change',function () {
var forum = "";
forum=$("select#forum_id :selected").val()
if (forum=='') {forum=0}
jQuery.get('/users/'+forum+'/update_group_options', function(data){
$("#group_div").html(data);
})
return false;
})
.change();
$("#county_council_id").live('change',function () {
var county_council = "";
county_council=$("select#county_council_id :selected").val()
if (county_council=='') {county_council=0}
jQuery.get('/users/'+county_council+'/update_forum_options', function(data){
$("#forum_div").html(data);
})
return false;
})
.change();
});
</script>
I think the "us" is written by js.
May be you can double check the js.

Using an AJAX call to update a rails page without a refresh?

I have a page on my site that lets users respond to invites by either accepting or declining them.
Their response is stored in the database as the boolean 'accepted', and is used to apply the classes 'selected' or 'not_selected' (selected makes the text orange) to the 'attending' div or the 'not attending' div.
<% #going, #not_going = invite.accepted ? ['selected','not_selected'] : ['not_selected','selected'] %>
<%= link_to(outing_invite_accept_path( { :outing_id => invite.outing_id, :invite_id => invite.user_id } )) do %>
<div class="attending_div <%= #going %>">
attending
</div>
<%end %>
<%= link_to(outing_invite_decline_path( { :outing_id => invite.outing_id, :invite_id => invite.user_id } )) do %>
<div class="attending_div <%= #not_going %>">
not attending</div>
</div>
<% end %>
When either div is clicked, it's diverted to the appropriate controller actions:
def invite_accept
#outing = Outing.find(params[:outing_id])
#invite = OutingGuest.find_by_outing_id_and_user_id(params[:outing_id], params[:invite_id])
#invite.update_attribute(:accepted, true)
redirect_to({:action => "index"})
end
def invite_decline
#outing = Outing.find(params[:outing_id])
#invite = OutingGuest.find_by_outing_id_and_user_id(params[:outing_id], params[:invite_id])
#invite.update_attribute(:accepted, false)
redirect_to({:action => "index"})
end
And as right now, this code works just fine. But it requires the index page be refreshed for it to take effect.
I know it's possible to update the page without a refresh using a jQuery ajax call attached to a listener on the appropriate div, but I have no idea what such a call would look like, or where to start, really...
You want to use rail's link_to :remote => true.
See http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
For dealing with callbacks you can bind to certain events that will trigger. For example:
<%= link_to "Click Me!", some_path, :class => 'ajax', :remote => true %>
<script>
jQuery(function($) {
$("a.ajax")
.bind("ajax:loading", console.log('loading'))
.bind("ajax:complete", console.log('complete'))
.bind("ajax:success", function(event, data, status, xhr) {
console.log(data);
})
.bind("ajax:failure", function(xhr, status, error) {
console.log(error);
});
});
</script>
This page is also a pretty good write up: http://www.simonecarletti.com/blog/2010/06/unobtrusive-javascript-in-rails-3/

How do I use the Quicksand jQuery plugin with a Rails AJAX request?

I am trying to use the Quicksand jQuery plugin to decorate the response of an AJAX call in Rails:
Link:
<% Project.services.each_with_index do |service, index| %>
<%= link_to_function(service, "regatherProjects('#{service}', #{index})", :id => "service_link_#{index}") %>
<%= " / " if !index.eql?(Project.services.length - 1) %>
<% end %>
JS:
function regatherProjects(service_name, service_id) {
$.get("/index_project_update", { service: service_name }, function(data) {
$('#home_projects').quicksand($(data), {
adjustHeight: 'dynamic'
});
});
$('#home_services').find('a').removeClass("on");
$('#service_link_' + service_id).addClass("on");
};
Controller:
def index_project_update
if params[:service] && !params[:service].blank?
#projects = Project.highlighted.where(:service => params[:service])
else
#projects = Project.highlighted
end
end
View:
$("#home_projects").replaceWith("<%= j(render('projects')) %>")
Projects:
<div id="home_projects">
<% if #projects.empty? %>
<p>No projects. <%= link_to_function("View All", "regatherProjects('')") %>.</p>
<% else %>
<ul class="all_projects">
<% #projects.each_with_index do |project, index| %>
<li data-id="<%= project.customer.name.underscore.downcase %>_<%= project.name.underscore.downcase %>">
<%= link_to(image_tag(project.project_images.first.image.home), project) %>
</li>
<% end %>
</ul>
<% end %>
</div>
I think the problem is that the data returned by the AJAX request (see below) is not in the format that Quicksand expects it to be in but I'm not sure how to extrapolate the relevant information from the response. The response from my AJAX request is something like:
$("#home_projects").replaceWith("<some><html><that><i><need>")
So, the problem is that it's using the above code as the destination code for the Quicksand call when it should be using the replacement HTML:
<some><html><that><i><need>
The AJAX request works perfectly fine, but I need to integrate Quicksand into here.
I need:
a better way to do this or;
a way to extrapolate the argument for replaceWith() in the aforementioned code to use as the destination code for Quicksand.
If I've omitted any information you think you need to help, please ask.
This is the first question I've asked on Stack Overflow so I feel obligated to apologise for any misusage.
If anyone runs into a similar issue, the following worked for me in Chrome, Firefox, IE9, IE8 and IE7.
Link:
<% Project.services.each_with_index do |service, index| %>
<%= link_to_function(service, "regatherProjects('#{service}', #{index})", :id => "service_link_#{index}") %>
<%= " / " if !index.eql?(Project.services.length - 1) %>
<% end %>
JS:
function regatherProjects(service_name, service_id) {
$.get("/index_project_update.html", { service: service_name }, function(data) {
$('.all_projects').quicksand($(data).find('li'), {
adjustHeight: 'dynamic'
});
});
$('#home_services').find('a').removeClass("on");
$('#service_link_' + service_id).addClass("on");
};
Route:
match '/index_project_update' => 'application#index_project_update', :defaults => { :format => 'html' }
Controller:
def index_project_update
if params[:service] && !params[:service].blank?
#projects = Project.highlighted.where(:service => params[:service])
else
#projects = Project.highlighted
end
render :layout => false
end
View:
<%= render('application/index/projects') %>
Projects:
<div id="home_projects">
<% if #projects.empty? %>
<ul class="all_projects">
<li data-id="project">No projects. <%= link_to_function("View All", "regatherProjects('')") %>.</li>
</ul>
<% else %>
<ul class="all_projects">
<% #projects.each_with_index do |project, index| %>
<li data-id="project_<%= project.id %>">
<%= link_to(image_tag(project.project_images.first.image.home, :alt => (project.customer.name + " - " + project.name), :title => (project.customer.name + " - " + project.name)), project) %>
</li>
<% end %>
</ul>
<% end %>
</div>

Refresh div with gmaps4rails (AJAX)

I'm using Rails 3.0.9 version, and jquery.
I've been using this gem without a database. It is used only for map display, and display KML file on it. For this I used:
<div id='ajax_map'>
<% #kmlurl="http://mysite/file1.kml" %>
<%= gmaps( :kml => { :data => "[{ url: #{#kmlurl.inspect}}]" } ) %>
</div>
All great shows.
I want to do that after you change the links (# kmlurl), and click on the button, the map updated with this new KML file. I use a separate action js.erb with the following code:
$('#ajax_map').html('<%= #kmlurl="http://mysite/file2.kml" %>'+'<br />'+'<%= gmaps( :kml => { :data => "[{ url: #{#kmlurl.inspect}}]" } ) %>');
But he does not update the DIV. "js.erb" rendered normally, without using the method of gmaps () it normally returns # kmlurl. I tested this same code in the ". Html.erb" in the tags , it loads a new file, but, of course, just when the page loads.
How can I solve this problem?
Solved the problem as follows (in js.erb):
$('#ajax_map').html('<%= escape_javascript( gmaps({:last_map => false}) ) %>');
Gmaps.map = new Gmaps4RailsGoogle();
Gmaps.load_map = function() {
Gmaps.map.map_options.maxZoom = 15;
Gmaps.map.initialize();
Gmaps.map.kml = [{ url: '<%= "#{#kmlurl}" %>'}];
Gmaps.map.create_kml();
Gmaps.map.adjustMapToBounds();
Gmaps.map.callback();
};
Gmaps.loadMaps();
First I would refactor things just a bit.
Say that first bit of code were in your index page. I'd move the setting of #kmlurl into the corresponding controller action:
def index
#kmlurl = "http://mysite/file1.kml"
end
Then (assuming index?) your index view would be simply:
<div id="ajax_map">
<%= gmaps( :kml => { :data => "[{ url: #{#kmlurl}}]" } ) %>
</div>
Then to add a link that will update the map:
<%= link_to 'Other Map', '/othermap', :remote=>true %>
Now you'd create a route in routes.rb:
match '/othermap' => 'foo#othermap'
Then in foo_controller.rb:
def othermap
#kmlurl = "http://mysite/file2.kml"
end
Then create othermap.js.erb:
$('#ajax_map').html(
'<%=
escape_javascript(
gmaps( :kml => { :data => "[{ url: #{#kmlurl}}]" } )
)
%>'
)
That's a quick fix, but what I would REALLY do is strive to make your view code as simple as possible, and do all the real work in the controller. Ideally your view would just be:
<div id="ajax_map">
<%= gmaps( :kml => { :data => #mapdata } ) %>
</div>
set up #mapdata as appropriate in your controller. You've got too much stuff that really belongs in a controller embedded in your view code! Your othermap.js.erb should be equally simplified. i.e.
$('#ajax_map').html('<%= escape_javascript(gmaps( :kml => { :data => #mapdata } ))%>')

Resources