Backbone Collection inheritance, two constructors - javascript

I am looking for a way to have a BaseCollection for all my collections for shared behavior.
I was able to successfully do it with shared functions, but I want some initialization logic to occur in the BaseCollection so that all my collections trigger an event 'model-change'. Is there a way for my BaseCollection to have a constructor - is the code below the best way to do it? I assume if I put two initialize functions or two constructor override functions then only one will get called. So it seems I can only use one of them each.
var BaseCollection = Backbone.Collection.extend({
constructor: function () {
var self = this;
this.on('change',function(model,property){
self.trigger('model-change',model,property);
});
Backbone.Collection.apply(this, arguments);
},
parse: function (resp) {
if (resp.success) {
return resp.success;
}
else if (resp.error) {
return this.models;
}
else {
return resp;
}
},
});
var UsersCollection = BaseCollection.extend({
constructor: function () { //this will override the constructor in BaseCollection, but I want both...
this.givenName = '#UsersCollection';
Backbone.Collection.apply(this, arguments);
},
initialize: function (models, opts) {
//do something here
}
});
Is there a better way to do it? One problem that I have is that I can't override constructor twice, I can only override it in the parent (BaseCollection) class. So is there a way to chain constructors? Or do I pretty much only have two options?

You can probably just extend and apply from the BaseCollection instead of the Backbone.Collection to get the results you want from your example:
var BaseCollection = Backbone.Collection.extend({
constructor: function () {
// your base collection constructor
// run the Backbone.Collection constructor on this
Backbone.Collection.apply(this, arguments);
}
});
// extends methods on BaseCollection
var UserCollection = BaseCollection.extend({
constructor: function () {
// your user collection constructor
// run the BaseCollection constructor on this
BaseCollection.apply(this, arguments);
}
});

Related

Backbone model: initialize vs. constructor

Reading through the docs, I see that you can replace the constructor for Backbone's extend on a model class. But what's the difference between doing this vs. doing it on the initialize method? Aren't both called when you use new?
var Library = Backbone.Model.extend({
constructor: function() {
this.books = new Books();
Backbone.Model.apply(this, arguments);
},
parse: function(data, options) {
this.books.reset(data.books);
return data.library;
}
});
vs.
var Library = Backbone.Model.extend({
initialize: function() {
this.books = new Books();
Backbone.Model.apply(this, arguments);
},
parse: function(data, options) {
this.books.reset(data.books);
return data.library;
}
});
"constructor" runs before Backbone sets up the structure.
"initialize" is called inside the structure's constructor function.
In other words if you need to add anything to the object before Backbone sets up the structure you might want to use "constructor". If you need to add something to your object after that Backbone sets up the structure you can use "initialize".
From: https://github.com/jashkenas/backbone/issues/720

Event specific methods are left dangling in Backbone.js?

The two methods below are in the top scope of backbone.js. However they are only used in Backbone.Events.
Why weren't they included as a property in the object literal passed to Backbone.Events like the other methods were?
Was this to keep them private and out of the user API?
// only used in Backbone.Events
eventsApi = function(obj, action, name, rest) {
// internals
};
// only used in Backbone.Events
triggerEvents = function(events, args) {
// internals
};
Was this to keep them private and out of the user API?
I'd say yes. Its the revealing module pattern.
var myModule = (function() {
var privateFn = function() { ... };
return {
publicFn: function() {
return privateFn();
}
};
}());
Or using the terms via backbone:
(function(){
// other backbone code
var eventsApi = function() { ... };
var Events = Backbone.Events = {
on: function() {
// code...
var whatever = eventsApi(some, args);
// code...
}
};
// other backbone code
}());
Now Events.Backbone.on is a function which can call the function eventsApi, even though the eventsApi function is not exposed publicly.

Backbone: Easiest way to maintain reference to 'this' for a Model inside callbacks

var JavascriptHelper = Backbone.Model.extend("JavascriptHelper",
{}, // never initialized as an instance
{
myFn: function() {
$('.selector').live('click', function() {
this.anotherFn(); // FAIL!
});
},
anotherFn: function() {
alert('This is never called from myFn()');
}
}
);
The usual _.bindAll(this, ...) approach won't work here because I am never initializing this model as an instance. Any ideas? Thanks.
You could do it by hand:
myFn: function() {
$('.selector').live('click', function() {
JavascriptHelper.anotherFn();
});
}
Or, if anotherFn doesn't care what this is when it is called (or if it wants this to be what live uses):
myFn: function() {
$('.selector').live('click', JavascriptHelper.anotherFn);
}
As an aside, live has been deprecated in favor of on. Also, if you're not instantiating your JavascriptHelper, then why is it a Backbone.Model at all? Why not use a simple object literal:
var JavascriptHelper = {
myFn: function() {
//...
},
anotherFn: function() {
//...
}
};
And what are you expecting this construct:
var JavascriptHelper = Backbone.Model.extend(string, {}, {...})
to leave you in JavascriptHelper? Extending a string is strange but passing three arguments to Backbone.Model.extend is pointless, it only cares about two arguments. If you want static properties then you should be passing them as the second argument:
var JavascriptHelper = Backbone.Model.extend({}, { myFn: ... });

Accessing parent class in Backbone

I need to call the initialize method of the parent class, from inside the inherited MyModel-class, instead of completely overwriting it as I am doing today.
How could I do this?
Here's what my code looks right now:
BaseModel = Backbone.Model.extend({
initialize: function(attributes, options) {
// Do parent stuff stuff
}
});
MyModel = BaseModel.extend({
initialize: function() {
// Invoke BaseModel.initialize();
// Continue doing specific stuff for this child-class.
},
});
Try
MyModel = BaseModel.extend({
initialize: function() {
BaseModel.prototype.initialize.apply(this, arguments);
// Continue doing specific stuff for this child-class.
},
});
MyModel = BaseModel.extend({
initialize: function() {
MyModel.__super__.initialize.apply(this, arguments);
// Continue doing specific stuff for this child-class.
},
});
This worked for me, when I was trying to inherit among my models:
MyModel.prototype.initialize.call(this, options);
Referenced from http://documentcloud.github.com/backbone/#Model-extend
Thanks.
I think it'd be
MyModel = BaseModel.extend({
initialize: function() {
this.constructor.__super__.initialize.call(this);
// Continue doing specific stuff for this child-class.
},
});
this seems to be almost a duplicate of Super in Backbone, so you want something like this:
Backbone.Model.prototype.initialize.call(this);
Similar to #wheresrhys, but I would use apply instead of call in case BaseModel.initialize is expecting arguments. I try to avoid processing the attributes map that can be passed to a Backbone Model upon initialization, but if the BaseModel were actually a View or a Collection then I might want to set options.
var MyModel = BaseModel.extend({
initialize: function() {
this.constructor.__super__.initialize.apply(this, arguments);
// Continue doing specific stuff for this child-class.
},
});
here's a multi generation callSuper method, just add it to your extending class.
callSuper: function (methodName) {
var previousSuperPrototype, fn, ret;
if (this.currentSuperPrototype) {
previousSuperPrototype = this.currentSuperPrototype;
// Up we go
this.currentSuperPrototype = this.currentSuperPrototype.constructor.__super__;
} else {
// First level, just to to the parent
this.currentSuperPrototype = this.constructor.__super__;
previousSuperPrototype = null;
}
fn = this.currentSuperPrototype[methodName];
ret = (arguments.length > 1) ? fn.apply(this, Array.prototype.slice.call(arguments, 1)) : fn.call(this);
this.currentSuperPrototype = previousSuperPrototype;
return ret;
}
You might consider rewriting your code using functional inheritance.
var BackBone=function(){
var that={};
that.m1=function(){
};
return that;
};
var MyModel=function(){
var that=BackBone();
var original_m1=that.m1;
//overriding of m1
that.m1=function(){
//call original m1
original_m1();
//custom code for m1
};
};

Javascript inheritance and method overriding

Assume I have a class like this:
function Widget() {
this.id = new Date().getTime();
// other fields
}
Widget.prototype = {
load: function(args) {
// do something
}
}
From this class I created some other classes which inherit the same prototype but have some added methods. What I want to do is being able to define a load() method in the sub-classes which first calls the parent method and then execute some code. Something like:
SpecialWidget.prototype = {
load: function(args) {
super.load(args);
// specific code here
}
}
I know there's no super keyword in Javascript but there must be a way to do this.
You can simulate it like this:
SpecialWidget.prototype = {
load: function(args) {
Widget.prototype.load.call(this, args);
// specific code here
}
}
Or you can create your own super property like this:
SpecialWidget.prototype.parent = Widget.prototype;
SpecialWidget.prototype = {
load: function(args) {
this.parent.load.call(this,args);
// specific code here
}
}
so first, you set up your 'subclass' like so
function SubClass(name) {
Super.call(this);
// stuff here
}
SubClass.prototype = new SuperClass(null);
SubClass.prototype.constructor = SubClass;
and then you can do
SuperClass.prototype.theMethod.apply(this);
from within a subclass implementation to specifically invoke the super's implementation.
I don't know if this is the best solution, but you could do something like this:
function Widget() {
this.id = new Date().getTime();
}
Widget.prototype.load = function(args) {
alert( 'parent load' );
};
SpecialWidget = function(){};
// Make the prototype of SpecialWidget an instance of Widget
var proto = SpecialWidget.prototype = new Widget;
// Give the prototype a function that references the "load" from Widget
proto.parent_load = proto.load;
// Give SpecialWidget its own "load" that first calls the parent_load
proto.load = function( args ) {
this.parent_load( args );
alert( 'special load' );
};
var inst = new SpecialWidget;
inst.load();
This makes the prototype of SpecialWidget an instance of Widget so that it inherits all that Widget has.
Then it makes a reference to the load() of Widget called parent_load(), and creates its own load() that calls the parent_load() when invoked.
Since mid-2015 (ECMAScript 2015), javascript has Classes and super
Here's the link: https://262.ecma-international.org/6.0/, see section 12.3.5 (super) and 14.5 (Class definitions).
How your code would look with those changes:
class Widget() {
constructor() {
this.id = new Date().getTime();
// other fields
}
load(args) {
// do something
}
}
class SpecialWidget extends Widget {
load(args) {
super.load(args);
// specific code here
}
}
The closest I got to the previous syntax (without using class but using super) was using Object.setPrototypeOf:
// UNCHANGED
function Widget() {
this.id = new Date().getTime();
// other fields
}
Widget.prototype = {
load: function(args) {
// do something
}
}
// slightly changed to declare SpecialWidget
function SpecialWidget() {}
// changed to define load as an method, and not a property with function as value
SpecialWidget.prototype = {
load(args) {
super.load(args);
// specific code here
}
}
// here's the key
Object.setPrototypeOf(SpecialWidget.prototype, Widget.prototype);
The declaration of load was changed because super can be used inside methods, but not functions. So, instead of load: function(args) { body }, it's simply load(args) { body }.
But, there's a caveat: with this solution, elements of SpecialWidget will not inherit the id defined as new Date().getTime(). I don't think there's a workahound (without using classes or duplicating code declaring this.id inside SpecialWidget).
It would be possible to store the old value of the load method in a closure, if you did your overriding like this:
function Widget() {
this.id = new Date().getTime();
// other fields
}
Widget.prototype = {
load: function(args) {
// do something
alert("Widget Prototype Load");
}
};
function SpecialWidget(){
};
SpecialWidget.prototype = new Widget();
(function(){
var oldLoad = SpecialWidget.prototype.load;
SpecialWidget.prototype.load = function(){
oldLoad();
alert("new Load");
};
}());
var x = new SpecialWidget();
x.load();
It works, but I'm not sure if it's the best method.
Using Simple Javascript Class:
Class.extend('Widget', {
load: function () {
alert('foo');
}
});
Widget.extend('SpecialWidget', {
load: function () {
this.super();
alert('bar');
}
});
new Widget().load(); // Alert: 'foo'
new SpecialWidget().load(); // Alert: 'foo' and 'bar'
Take a look at Simple Javascript Class Project, Simple JavaScript Inheritance and Inheritance Patterns in JavaScript.

Categories

Resources