Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't extend backbone.events in coffeescript

I'm getting the error:

Uncaught TypeError: Cannot read property 'constructor' of undefined 

When declaring the following class:

 class ViewHelpers extends Backbone.Events

I can use the same syntax to extend Backbone.Router, Views, Model etc. Here is the compiled javascript which I wrote in a quick log to make sure Backbone.Events was there

__t('views').ViewHelpers = (function(_super) {

 #how i know it is definied here
 console.log(_super.trigger)

 __extends(ViewHelpers, _super);

 function ViewHelpers() {
   return ViewHelpers.__super__.constructor.apply(this, arguments);
 }

 return ViewHelpers;

})(Backbone.Events);

So the line causing the error is

ViewHelpers.__super__.constructor.apply(this, arguments);

What is different about __extends() method that it would work for Backbone.View and not Backbone.Events?

like image 770
benipsen Avatar asked Jun 17 '12 00:06

benipsen


2 Answers

That's because Backbone.Events is not a "class", so it cannot be extended, it's a "module" that can be mixed-in into other objects (see docs here). In JavaScript terms that means that it's not a Function, that can be called as a constructor (i.e. new Backbone.Events will throw an error), it's just a plain JS object whose properties (methods) can be assigned to other objects to make them event dispatchers.

In CoffeeScript, you can mix-in the Backbone.Events into your objects when they are created:

class ViewHelpers
  constructor: ->
    _.extend @, Backbone.Events

Or you can just extend the class' prototype and avoid having those methods as (own) properties of all ViewHelpers instances:

class ViewHelpers
  _.extend @prototype, Backbone.Events

These two approaches should work and let you instantiate and use ViewHelpers as event dispatchers:

vh = new ViewHelpers
vh.on 'foo', -> alert 'bar'
vh.trigger 'foo'​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
like image 145
epidemian Avatar answered Nov 13 '22 15:11

epidemian


There's another way (from what @epidemian answered), which doesn't involve copying Backbone.Events into a new object to use as your prototype - instead, use Object.create to create a new object to use as your prototype, using Backbone.Events as its prototype.

class ViewHelpers
  @prototype = Object.create(Backbone.Events)

Now ViewHelpers' prototype is a new, empty object whose prototype is Backbone.Events. You can define methods on ViewHelpers' prototype without affecting Backbone.Events, but all the Backbone.Events methods are still available to ViewHelpers, without having to copy them into a new object. This not only saves (a miniscule amount of) memory, but if you ended up adding on to Backbone.Events later, all ViewHelperss would see the change.

For this, you'll need either a browser that has ES5's Object.create function, or an Object.create polyfill.

like image 24
bhollis Avatar answered Nov 13 '22 15:11

bhollis