【问题标题】:Google Maps for Rails - update markers with AJAXGoogle Maps for Rails - 使用 AJAX 更新标记
【发布时间】:2015-02-11 14:20:55
【问题描述】:

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

我想使用 Ajax 来避免刷新页面。所以我在表单中添加了remote: true,在控制器中添加了一个respond_to,并且一个新的search.js.erb. My 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 %>");

【问题讨论】:

  • 嗨席琳。我正在解决一个类似的问题;我很欣赏你的问题和你得到的答案。我想知道您是否可以分享您的表格的外观。此外,当您最初加载搜索页面时,不会向控制器发送任何内容,因此这些区域是空的;你设置一个默认值吗?我正在尝试使用视图页面通过 geolocatoin 获取用户的位置,然后将该信息发送回控制器以获取附近的所有标记,但我不确定如何,因为信息流的顺序不是传统的。顺便说一句,您的页面看起来非常棒。
  • 您好,You can find my form here。此表单位于 index.html.erb 中,并向 /search 发送一个请求,其中包含与搜索相对应的参数,因此它永远不会为空。您可以获取用户的位置(使用 IP 地理编码和 Geokit for example ),然后获取附近的所有标记并将它们发送到视图。

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


【解决方案1】:

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

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

创建一个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);
})();

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

【讨论】:

  • 嗨,奥利维尔。谢谢回答!你的回答很好,谢谢!!您的 map.js 中只有一个小错字。这是map 不是handler。我唯一的问题是变焦。一开始它设置正确(符合答案),但在第二次调用时(即使用 ajax 而不是 html)它显示法国并且没有放大。但我会自己解决这个问题。再次感谢!
  • 嗨 Olivier 和 Celine,感谢您发布这个问题和答案。我正在尝试类似的东西,您的回答对我非常有用!我也是 Rails 的新手,尤其是 javascript。我已经实现了大部分解决方案,但我想解决一件事,那就是:当我平移和缩放时,我会不断地重新提交搜索以根据需要删除/添加标记。这可行,但如果屏幕上已经存在相同的标记,我不想删除并重绘相同的标记。如何针对搜索返回的新 @hash 测试现有 __markers?
  • 这是我尝试过但不起作用的方法:我在 var __markers 下方创建了一个名为“var __oldHash”的新变量。然后我做了一个 _.isEqual(__oldHash, markersData) 来查看它们是否相同,如果它们不一样,那么它会遍历整个 UpdateMarkers 函数,最后我会设置 __oldHash = markersData.切片(0)。无论出于何种原因,如果我在分配后立即检查 isEqual,那么它当然是 True。但在顶部,即使我认为它们应该相同,它也总是错误的......
  • 我不知道为什么 __markers 会持有对地图上所有标记的引用,但是我的 __oldHash,在同一个地方声明,每次调用函数时都是空的......我会针对 __markers 本身进行测试,但我似乎无法做到这一点,因为我必须在创建 __newMarkers 时重建地图才能对其进行检查,从而达到目的......
  • 嘿@kindofgreat,我认为您应该为此提出自己的问题,以便您可以粘贴代码并更好地解释您的情况;)
【解决方案2】:

我尝试了同样的事情,但不是更新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

【讨论】:

  • 你好 Milind,所以我将 div map_container 移动到部分但地图现在不想初始化。我不明白,因为@hash 给出了正确的答案......我需要在索引中移动 javascript 吗?但是,如果 javascript 在索引中,我该如何更改我的标记?
  • 我已经用代码更新了答案。请检查一下。希望它能帮助你:)...@CélineMartinetSanchez
猜你喜欢
  • 1970-01-01
  • 2017-06-28
  • 2013-12-28
  • 2011-09-05
  • 1970-01-01
  • 1970-01-01
  • 2012-03-26
  • 2012-01-28
相关资源
最近更新 更多