2015-02-11 2 views
1

Я работаю над веб-приложением, и я использую Ruby on Rails. Наш индекс составлен из карты и поля поиска. Вы можете искать местоположение, и карта обновляет свои маркеры.Google Maps for Rails - обновить маркеры с помощью AJAX

Я бы хотел использовать 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 %>"); 
+0

Hi Celine. Я работаю через несколько схожую проблему; Я ценю ваш вопрос и ответы, которые вы получили. Мне было интересно, можете ли вы поделиться тем, как выглядит ваша форма. Кроме того, когда вы первоначально загружаете страницу поиска, ничто не посылается на контроллер, поэтому зоны поэтому пусты; вы устанавливаете значение по умолчанию? Я пытаюсь использовать страницу просмотра, чтобы получить местоположение пользователя через geolocatoin, а затем отправить эту информацию обратно контроллеру, чтобы закрыть все маркеры, но я не уверен, как с тех пор, как порядок информационного потока не является традиционным. Кстати, ваша страница выглядит действительно замечательно. – kindofgreat

+0

Здравствуйте, [Вы можете найти мою форму здесь] (http://pastie.org/9991159). Эта форма находится в index.html.erb и отправляет запрос/поиск с параметрами, соответствующими поиску, поэтому он никогда не пуст. Вы можете получить местоположение пользователя (используя геокодирование IP с помощью [Geokit например] (https://github.com/geokit/geokit-rails)), затем закройте все маркеры и отправьте их в представление. –

+0

Спасибо, Селин! – kindofgreat

ответ

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

Вот оно! Надеюсь, это приведет вас к следующему шагу вашего проекта :)

+0

Привет Оливье. Спасибо за ответ! Ваш ответ работает очень хорошо, спасибо! В вашей map.js. есть только незначительная ошибка опечатки. Это 'map' не' handler'. Единственная проблема, связанная с масштабированием.Вначале он правильно устанавливает (соответствует ответам), но при втором вызове (т. Е. Используя ajax, а не html) он показывает Францию ​​и не приближается. Но я сам это выясню. Еще раз спасибо! –

+0

Привет Оливье и Целин, спасибо, что опубликовали этот вопрос и ответ. Я пытаюсь что-то подобное, и ваши ответы были очень полезны для меня! Я тоже новичок в рельсах и особенно в javascript. Я реализовал большую часть решения, но мне нужно кое-что исправить, и вот это: когда я панорамирую и увеличиваю масштаб, я постоянно возвращаю поиск для удаления/добавления маркеров по мере необходимости. Это работает, но если окажется, что те же маркеры уже на экране, я не хочу удалять и перерисовывать одни и те же маркеры. Как я могу проверить существующие __маркисты на новый @hash, который возвращается из поиска? – kindofgreat

+0

Это то, что я пробовал, но не работает: я создал новую переменную под названием var __oldHash прямо под var __markers. Затем я сделал _.isEqual (__ oldHash, markersData), чтобы увидеть, были ли они одинаковыми, а если они не были, то он прошел бы через всю функцию UpdateMarkers, а в конце я бы установил __oldHash = markersData. срез (0). По какой-то причине, если я проверю isEqual сразу после назначения, тогда, конечно, это правда. Но наверху, даже когда я думаю, что они должны быть одинаковыми, это всегда ложно .... – kindofgreat

1

Я попробовал то же самое, но вместо обновления вы должны включить карту в 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

+0

Здравствуйте, Milind, Итак, я переместил div 'map_container' в частичный, но карта не хочет инициализировать сейчас. Я не понимаю, потому что @hash дает правильный ответ ... Мне нужно переместить javascript в индекс? Но как я могу изменить свои маркеры, если javascript находится в индексе? –

+0

Я обновил ответ с кодом .please проверить его. Надеюсь, это поможет вам:) ... @ CélineMartinetSanchez – Milind

Смежные вопросы