TL;DR
Is PinView.prototype = _.extend(PinView.prototype, google.maps.OverlayView.prototype)
the "proper" way to have a Backbone View inherit from another "class"?
Long read
We're redoing our site using Backbone and are working on including some mapping functionality.
I've got a Backbone view that handles placing <div>
s onto specific points within the browser window; this seems like a natural thing to extend in order have Google's Map API place them on geographical coordinates.
According to the Google API, in order to generate a custom overlay you create a new object and set the prototype for that object to a new instance of google.maps.OverlayView. You then implement three functions on top of that object so that the object responds to:
onAdd
draw
onRemove
Where onAdd
is responsible for generating the HTML and then applying it on top of the Map. This subsequently calls draw
which positions the element correctly according to the LatLng pairs and bounds you've provided. onRemove
gets called when you want to get rid of your layer.
So I've modified my View to include these three methods (which just call render and unrender and are bound to my collection). And then to make "the magic happen" I'm doing:
PinView.prototype = _.extend(PinView.prototype, google.maps.OverlayView.prototype)
Does this look right? I can post the code for the View and the Model on which it's based, but honestly, they're irrelevant to this example -- the code works and I'm able to place custom div
s generated through Backbone model, view and controller components on the map without a issue, what I'm asking I guess (and maybe this question is more apropos for programmers.se, so let me know and I'll move it).
This seems to be the easiest way to make my PinView both a Backbone View and a Google Maps OverlayView, but I'm not 100% comfortable with prototypal inheritance to know if I'm doing something "wrong" or breaking something somewhere down the road.
Nice idea! I'm usually a bit sceptical about weather or not you're 'correct' when things work so if you haven't run into a showstopper and the overlays shows up and does what the're supposed to do I'd say you are.
One thing to check out closer, though:
This isn't (and can't) be "real" multiple inheritance - that concept isn't really relevant in a prototype based language: one implementation of a method will inevitable "win" and overwrite the other implementation, at least when using _.extend()
This means that if there are members or methods with the same names in Backbone.View
and google.maps.OverlayView
the one last in your _.extend()
call will be the one that takes over. But when I inspect them using Chrome's Developer Tools I didn't see any obvious collision of this kind.
So my recommendation: continue using this, just test a lot. I'd love to see an example of this technique some time.
Ah! So I've been doing the above, but it's never felt right.
Then I found this discussion on a Backbone group which leads me to the following:
var MyView = (function(){
var view = function(){
Backbone.View.apply(this, arguments);
};
view.extend = Backbone.View.extend;
_.extend(view.prototype, Backbone.View.prototype, google.maps.OverlayView.prototype, [other prototypes...], { [VIEW DEFINITION] });
return view;
}());
This way if we need to override any of the definitions in a class we're extend
ing from, we can since it's earlier in the _.extend
chain (later definitions overwrite earlier definitions).
I'm working on 'extending' extend
to keep track of the "parent" object's references that would be overridden and providing a method to call them still (like Python's super
call). I haven't decided if this should be done through monkey-patching, an intercepter pattern (via underscore's _.tap()
method or something else, but I think it'll add a lot of flexibility.
This would allow you to define an initialize
view in your "parent" class which could be called by doing something like _.super('ParentClass', 'initialize');
at the end of the "child" class's initialize
routine...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With