Google Maps for Rails - Update Markers with AJAX

I am working on a web application and I am using Ruby on Rails. Our index is composed of a map and a search field. You can find the location and the map will update its markers.

I would like to use Ajax so as not to refresh the page. So I added remote: true to the form, respond_to to the controller, and the new search.js.erb. My search.js.erb displays a partial _googlemap.erb that contains a script to initialize the map.

Here is my problem. Since the map already exists, it looks like I would like to create the same object twice, which, of course, does not work, and this is terrible. I would like to update only the markers on the map with new ones. But I can’t find a way to do this.

I saw that the previous version of Gmaps4rails integrated the way to do this ( Gmaps.map.replaceMarkers(your_markers_json_array); ), but now it does not work. When I use it, I got this error: " TypeError: Gmaps.map is undefined ". I tried with " handler.replaceMarkers(); " but this time I have " TypeError: handler.replaceMarkers is not a function ".

I am new to Javascript and Rails, but I want to improve my knowledge and I really need to continue working with this web application. I searched for a solution everywhere on the Internet, but in vain.

Live site here

Please can someone tell me how can I do this and what am I doing wrong?

MANY thanks in advance

Celine

zones_controller.rb

 def search respond_to do |format| format.html.none do search_params = params[:zone][:search] coordinates = Geocoder.coordinates(search_params).join(",") @zones = Zone.search( "", { "aroundLatLng" => coordinates, "aroundRadius" => 500000 #Searches around 500 km }) if coordinates.nil? @zones = Zone.search(params[:search]) elsif @zones.empty? @zones = Zone.all flash[:error] = "No zone could be found. Please try again." end build_map(@zones) end format.js end end def build_map(array) @hash = Gmaps4rails.build_markers(array) do |zone, marker| marker.lat zone.latitude marker.lng zone.longitude marker.json({ title: zone.description, id: zone.id }) marker.infowindow render_to_string(:partial => "/zones/map_box", locals: { zone: zone }) end end 

search.html.erb

  <div id="map" style='width: 100%; height: 700px;'> </div> <!-- Beginning Google maps --> <script type="text/javascript" id="map_script"> $(document).ready(function() { <%= render 'googlemap', hash: @hash %> }); // Document ready </script> 

_googlemap.erb

 handler = Gmaps.build('Google'); handler.buildMap({ provider: { disableDefaultUI: true, mapTypeId: google.maps.MapTypeId.TERRAIN }, internal: {id: 'map'} }, function(){ markers_json = <%= raw hash.to_json %>; markers = _.map(markers_json, function(marker_json){ marker = handler.addMarker(marker_json); handler.getMap().setZoom(4); _.extend(marker, marker_json); marker.infowindow = new google.maps.InfoWindow({ content: marker.infowindow }); return marker; }); handler.bounds.extendWith(markers); handler.fitMapToBounds(); }); 

search.js.erb

 $('#map_script').replaceWith("<%= render 'googlemap', hash: @hash %>"); 
+1
source share
2 answers

Why don't you just update the map with new markers? The value, instead of re-rendering the entire map after each search, simply updates the markers on the existing map, removing all markers and adding new ones.

I have not tested the method, but I think it should work and be more efficient:

Create the app/assets/javascript/map.js . Here you can store your card related functions. Create a function to update map markers in this file:

map.js

 (function() { /* __markers will hold a reference to all markers currently shown on the map, as GMaps4Rails won't do it for you. This won't pollute the global window object because we're nested in a "self-executed" anonymous function */ var __markers; function updateMarkers(map, markersData) { // Remove current markers map.removeMarkers(__markers); // Add each marker to the map according to received data __markers = _.map(markersData, function(markerJSON) { marker = map.addMarker(markerJSON); map.getMap().setZoom(4); // Not sure this should be in this iterator! _.extend(marker, markerJSON); marker.infowindow = new google.maps.InfoWindow({ content: marker.infowindow }); return marker; }); map.bounds.extendWith(__markers); map.fitMapToBounds(); }; // "Publish" our method on window. You should probably have your own namespace window.updateMarkers = updateMarkers; })(); 

This function can be used to initialize your card and update it. Since you won’t (if my answer suits you) double-display the map, you can delete _google_map.erb and return its contents to search.html.erb , but using the function you just created:

search.html.erb

  <div id="map" style='width: 100%; height: 700px;'> </div> <!-- Beginning Google maps --> <script type="text/javascript" id="map_script"> $(document).ready(function() { mapHandler = Gmaps.build('Google'); mapHandler.buildMap({ provider: { disableDefaultUI: true, mapTypeId: google.maps.MapTypeId.TERRAIN }, internal: {id: 'map'} }, function(){ var markersData = <%= raw @hash.to_json %>; updateMarkers(mapHandler, markersData); }); }); // Document ready </script> 

Please do not forget the var keyword when declaring variables, otherwise they will become global, and this is bad ^^
Note that I intentionally left mapHandler as a global variable: you will need access to your handler to update tokens later when someone uses a search. This is probably not an ideal thing, but this question is not about refactoring your code, so keep it that way.

So, now my solution brings you a map that initializes with the given markers when the page loads. In other words, nothing has changed!

However, now you can reuse this updateMarkers function to change the markers displayed on your map. This is what you need a search.js.erb script:

search.js.erb

 (function() { var markersData = <%= raw @hash.to_json %>; updateMarkers(mapHandler, markersData); })(); 

What is it! I hope this takes you to the next stage of your project :)

+3
source

I tried the same thing, but instead of updating the marker you should include the map in partial/placeholder and then update it ...

for example, this view showing a map ... I will update this view / placeholder with the latest map and markers

 <div id="map_users_index"> <div id="map" class="map" style="height:relative;"> </div> 

in users_controller.rb

  ##take index action or any other action def index ##do your stuff and get more users respond_to do |format| format.html format.js end end 

in index.js.erb

 ##update the placeholder/partial with new map with new markers $("#map_users_index").html("<%= escape_javascript(render(:partial => 'index')) %>"); 

I have my own working code ... HERE

+1
source

Source: https://habr.com/ru/post/1266541/


All Articles