Description
With the final changes to the ES6 class spec (details here), it's no longer possible to use ES6 classes with Backbone without making significant compromises in terms of syntax. I've written a full description of the situation here (make sure to click through to the comments at the bottom for an additional mitigating option), but essentially there is no way to add properties to an instance of a subclass prior to the subclasses parents constructor being run.
So this:
class DocumentRow extends Backbone.View {
constructor() {
this.tagName = "li";
this.className = "document-row";
this.events = {
"click .icon": "open",
"click .button.edit": "openEditDialog",
"click .button.delete": "destroy"
};
super();
}
initialize() {
this.listenTo(this.model, "change", this.render);
}
render() {
//...
}
}
is no longer valid in the final ES6 spec. Instead you effectively have 3 (not very appealing) options if you want to try to make this work:
Attach all properties as functions
Backbone allows this, but it feels dumb to write something like this:
class DocumentRow extends Backbone.View {
tagName() { return "li"; }
className() { return "document-row";}
events() {
return {
"click .icon": "open",
"click .button.edit": "openEditDialog",
"click .button.delete": "destroy"
};
}
initialize() {
this.listenTo(this.model, "change", this.render);
}
render() {
//...
}
}
compared to the current extends syntax
Run the constructor twice
I don't view this as a real option due to the issues it would cause running initialize a second time with different cids, etc.
Pass all properties as default options to the superclass constructor
This was suggested by a commenter on my blog and is probably the most practical current option. It looks something like this:
class MyView extends Backbone.View {
constructor(options) {
_.defaults(options, {
// These options are assigned to the instance by Backbone
tagName: 'li',
className: 'document-row',
events: {
"click .icon": "open",
"click .button.edit": "openEditDialog",
"click .button.delete": "destroy"
},
// This option I'll have to assign to the instance myself
foo: 'bar'
});
super(options);
this.foo = options.foo;
}
}
Since all of these current options involve clear compromises relative to the current Backbone extends syntax, it would be wonderful if a better solution could be developed. I'm not totally sure what this should look like, but one idea that came to mind while I did the writeup for my blog was the addition of a "properties" function that would output a hash of properties. The constructor could then run that function and add them to the instance prior to the other processing done by the constructor.