In the past, I read a lot about compositability over inheritance, and I completely sell this concept and use this principle a lot in my code.
However, I run into problems in everyday work, where inheritance tends to creep in views, and I'm struggling to figure out how I can implement something more complex (the fact that I use Backbone on my day does not help for day work). They are usually when I want to use all the features of an existing Backbone view, adding some extra features on top.
Take this hypothetical example, where we have an e-commerce type page with several views Product, each of which is a set of options available for the basket for a specific product:
var ProductView = (function(Backbone, JST) {
'use strict';
return Backbone.View.extend({
className: 'product',
template: JST['application/templates/product']
initialize: function(options) {
this.options = options || {};
this.collection.fetch();
this.listenTo(this.collection, 'loaded', this.render);
},
render: function() {
this.$el.html(
this.template(this.collection)
);
return this;
},
}, {
create: function(el) {
var endpoint = '/api/options/' + el.getAttribute('data-basket-id') + '/' + el.getAttribute('data-product-id');
new ProductView({
el: el,
collection: new ProductCollection(null, { url: endpoint })
});
}
});
})(Backbone, JST);
Suppose we want to display some products that require the visitor to be requested using the confirmation window (say, for insurance reasons, this particular product must be sold with insurance, so we need to send a request to the user about this when they add it to their basket):
var InsuranceProductView = (function (_, ProductView) {
'use strict';
return ProductView.extend({
consentTemplate: JST['application/templates/product/insurance_consent'],
initialize: function (options) {
this.listenTo(this.model, 'change:selected', function (model) {
if (!model.get('selected')) {
this.removeMessage()
}
});
ProductView.prototype.initialize.apply(this, arguments);
},
events: function () {
return _.extend({}, ProductView.prototype.events, {
'change input[type=radio]': function () {
this.el.parentElement.appendChild(this.consentTemplate());
},
'change .insurance__accept': function () {
ProductView.prototype.onChange.apply(this);
},
});
},
removeMessage: function () {
var message = this.el.parentElement.querySelector('.insurance__consent');
message.parentNode.removeChild(message);
},
});
})(_, ProductView);
Is there a more complicated way to write this? Or is it a situation where the right thing to break through inheritance is?