Google Maps for Rails - 使用AJAX更新标记

时间:2015-02-11 14:20:55

标签: ruby-on-rails ajax google-maps gmaps4rails

我正在开发一个Web应用程序,我使用Ruby on Rails。我们的索引由地图和搜索字段组成。您可以搜索位置,地图会更新其标记。

我想使用Ajax来避免刷新页面。因此,我在表单中添加了remote: true,在控制器中添加了respond_to,并且新的search.js.erb.我的search.js.erb呈现了部分_googlemap.erb,其中包含用于初始化地图。

这是我的问题。由于地图已经存在,就好像我想要创建两次相同的对象,这当然不起作用并且非常糟糕。我想用新的标记更新地图中的标记。但我找不到办法做到这一点。

我看到之前版本的Gmaps4rails集成了一种方法(Gmaps.map.replaceMarkers(your_markers_json_array);),但它现在似乎不起作用。当我使用它时,我收到了这个错误:“TypeError: Gmaps.map is undefined”。我试过“handler.replaceMarkers();”,但这次我有“TypeError: handler.replaceMarkers is not a function”。

我是Javascript和Rails的新手,但我想提高自己的知识,我真的需要继续使用这个网络应用程序的其余部分。我一直在寻找互联网上的解决方案但是徒劳无功。

Live website here

拜托,有人可以告诉我我该怎么做以及我做错了什么?

提前多多感谢,

席琳

  

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 %>");

2 个答案:

答案 0 :(得分:3)

为什么不用新标记更新地图?这意味着,不是在每次搜索后重新渲染整个地图,只需通过删除所有标记并添加新标记来更新现有地图上的标记。

我还没有验证该方法,但我想它应该有效并且效率更高:

创建app/assets/javascript/map.js文件。您可以在那里存储与地图相关的功能。创建一个函数来更新此文件中的地图标记:

  

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;
})();

此功能可用于初始化地图并进行更新。你不会(如果我的回答满足你)将地图渲染两次,你可以删除_google_map.erb并将其内容放回search.html.erb,但使用我们刚刚创建的函数:

  

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>

在声明变量时请不要忘记var关键字,否则它们最终会成为全局变量,而这很糟糕^^
请注意,我故意将mapHandler作为全局变量:当有人使用搜索时,您需要访问处理程序以更新标记。这可能不是一个理想的事情,但这个问题不是重构你的代码所以让我们保持这种方式。

所以现在我的解决方案为您提供了一个在页面加载时使用给定标记初始化的地图。换句话说,一切都没有改变!

但是,您现在可以重复使用此updateMarkers功能来更改地图上显示的标记。这就是你search.js.erb脚本应该做的事情:

  

search.js.erb

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

就是这样!希望它能带你进入项目的下一步:)

答案 1 :(得分:1)

我尝试过同样的事情,但不是更新marker,而是应该在partial/placeholder中添加地图,然后更新它......

例如,这是显示地图的视图...我将使用最新地图和标记更新此视图/占位符

<div id="map_users_index">
<div id="map" class="map" style="height:relative;">
</div>
在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
index.js.erb

中的

##update the placeholder/partial with new map with new markers

$("#map_users_index").html("<%= escape_javascript(render(:partial => 'index')) %>");

我有自己的工作代码...... HERE