Search code examples
ruby-on-railsgoogle-mapsgmaps4railsgmaps4rails2

gmap4rails load and add infobox only when marker clicked


I'm using gmap4rails v2 with rails 4.1 and instead of loading all of the infoboxes at once, which is very inefficient, I would like to only load the contents for the info box of a particular marker once that marker is clicked. I came up with the following to select the marker.

markers = handler.addMarkers(<%= raw(@hash.to_json) %>);
        _.each(markers, function(marker){
          google.maps.event.addListener(handler.getMap(), 'click', function(){
            marker.infowindow();
          });
        }); 

But I'm not sure how I can send a query to my user table to get the needed attributes for example User.name, User.photo that will be used in the infobox.

The full gmaps handler is here:

var handler = Gmaps.build('Google', { markers: { maxRandomDistance: null, clusterer: undefined } }),


  maxZoom = 14;


  handler.buildMap({ 
     provider: {
      mapTypeControl: false,
      mapTypeId: google.maps.MapTypeId.ROADMAP,
      streetViewControl: false,
      doClustering: false,
      minZoom: 5  
    },
    internal: {id: 'big_map'}}, 
    function(){

    markers = handler.addMarkers(<%= raw(@hash.to_json) %>);
    _.each(markers, function(marker){
      google.maps.event.addListener(handler.getMap(), 'click', function(){
        marker.infowindow();
      });
    });
    handler.map.centerOn([$("#big_map").data("lat"),$("#big_map").data("lng")]);
    handler.getMap().setZoom(15);
    //handler.bounds.extendWith(markers);
    //handler.fitMapToBounds();
  });

controller which loads marker info:

return Gmaps4rails.build_markers(profiles) do |profile, marker|
  marker.lat profile.latitude
  marker.lng profile.longitude
  marker.json({ :id => profile.profile_code })
  # this is how I loaded all markers before: marker.infowindow render_to_string(partial: "info_window", locals: { profile: profile })
  marker.picture({
    url: view_context.image_path( "marker-#{ (profile == current_user.profile) ? 'green' : 'blue' }.png"),
    width:  32,
    height: 32
  })
end

Is there any way I could send a partial to the infowindow() function like I did in the original markers load as seen below? And if so how would I send the user.id to the partial (in my case it's profile.profile_code which I set each marker.id to equal that I think.

UPDATE:

Ok I now realize I need to make a request to the server, which javascript can't do so I'm going to try to use ajax by using

markers = handler.addMarkers(<%= raw(@hash.to_json) %>);
_.each(markers, function(marker){
  google.maps.event.addListener(handler.getMap(), 'click', function(){
    var infowindow = marker.infowindow;
    $.post('<%= load_info_box_url %>', {
    }, function(data){
      infowindow.html(data).name %>)
      infowindow.open(Gmaps.map.map, marker);
    });
  });
});

followed by making a load_info_box route and then requesting the necessary data in a controller, sending back html to data!


Solution

  • @apneadiving had a great answer but I found it a bit hard implementing links, conditionals and styling into javascript templates so I ended up using the ajax approach.

    javascript:

    markers = handler.addMarkers(data.markers);
            _.each(markers, function(json, index){
              json.marker = markers[index]; 
              google.maps.event.addListener(json.marker.getServiceObject(), 'click', function(){
                var infowindow = json.marker.infowindow;
    
                $.post('<%= load_infobox_url %>', {
                  marker_id: data.markers[index].id
                }, function(data){
                  infowindow.setContent(data.html);
                  infowindow.open(map, google.maps.markers[index]);
                });
    
              });
            });
    

    routes

    post '/load_infobox', to: 'requests#load_infobox', as: 'load_infobox'
    

    controller action:

    def load_infobox
        profile = Profile.find_by(profile_code: params[:marker_id])
        render json: { html: render_to_string(partial: "info_window", locals: { profile: profile }) }
      end