4

I am trying to build an application based on backbone.js and leaflet. Users could drag the map and see markers on the map. Markers can be selected by clicking on them. When selected they have to change their icon and the marker detailed information shown on a (not popup).

my backbone model consists of several entities:

Marker model contains latitude, longitude type, title, isSelected

Map model contains: center of the map, markers collection, selected marker

anyone has any idea how i could make this kind of functionality? how can i make leaflet markers as backbone views?

1 Answer 1

2

Backbone views and the leaflet object model are not a perfect fit, because the markers aren't contained within a DOM element, which is what Backbone.View.el is supposed to represent. Markers do of course have an element (accessible via marker._icon), but it doesn't exist until the marker is rendered to the map.

That said, you can represent the markers with Backbone views, you just can't use the events or any el related functionality. I've implemented similar views successfully using OpenLayers, which has the same "problem", and it works fine.

I think this is easiest to explain with code:

//MarkerView has no element
App.Views.MarkerView = Backbone.View.extend({

    initialize: function(options) {
        //pass map instance to the marker
        this.map = options.map;
        //create the marker object
        this.marker = L.marker([this.model.get('longitude'), this.model.get('latitude')]);
    },

    render: function() {    
        //append marker to the map
        this.marker.addTo(this.map);

        //can't use events hash, because the events are bound
        //to the marker, not the element. It would be possible
        //to set the view's element to this.marker._icon after
        //adding it to the map, but it's a bit hacky.
        this.marker.on('click', this.onClick);
    },

    onClick: function() {
        alert("click");
    }
});

//MapView renders a map to the #map element
App.Views.MapView = Backbone.View.extend({
    id:"#map",
    render: function() {
        //render map element
        var map = this.map =  L.map(this.$el.attr('id'))
            .setView([this.model.get('centerLon'),  this.model.get('centerLat') ], 13)
            .addLayer(L.tileLayer(this.model.get('layerUrl'), { maxZoom: 18 }));

        //render each marker
        this.markerViews = this.model.get('markers').map(function(marker) {
            return new App.Views.MarkerView({model:marker, map:map}).render();
        });
    }
});

Here's a demo on JSFiddle.

4
  • JSFiddle is probably down at the moment. why did you choose OpenLayers and not Leaflet? and from your answer i guess that currently there is no maps API which would be somewhat MVC oriented as Backbone.js is Commented Jan 25, 2013 at 10:24
  • @LaurynasMališauskas, it often is, but it'll bounce back. There's not much more in the fiddle than what I posted, just a demo using those views.
    – jevakallio
    Commented Jan 25, 2013 at 10:25
  • @LaurynasMališauskas I've used OpenLayers because my requirements are a bit more complex than what Leaflet can provide. Leaflet is lightweight, and great for simple maps and features, but for certain types of applications it just doesn't cut it. If all I needed were rendering tile map services and markers, I'd use Leaflet too.
    – jevakallio
    Commented Jan 26, 2013 at 12:07
  • I had to change id:"#map" to id:"map" in App.Views.MapView to get your jsfiddle to work. Here's my fork: jsfiddle.net/dPqQy Thanks for your example code!
    – Sam Hiatt
    Commented Nov 24, 2013 at 1:44

Not the answer you're looking for? Browse other questions tagged or ask your own question.