3
votes

I've run into this problem as I think I'm understanding Backbone incorrectly.

I have a super class called Runnable and a set of sub classes inherited from it:

var Runnable = Backbone.Model.extend({
    template: $("#template"),

    defaults: function(){
        return {
            id: '',
            alwaysOn: false,
        }
    }

    run: function() {
    }
});

var RunnableSubModel = Runnable.extend({
    run: function() {
        //do some custom stuff here
    }
});

... any many more runnable sub models ...

Now I want to have a Collection of Runnable sub models that I can get by ID and call the new run method:

var RunnableList = Backbone.Collection.extend({
    model: Runnable,

    run: function() {
        this.each(function(runnable) { 
            runnable.run();
        });
    }
});

RunnableList.push([
        new RunnableSubModel({id: 'mySubModel', alwaysOn: true})
    ]);

//POST EDIT (forgot this)
var lst = new RunnableList();

//doesn't work, looks for Runnable id value
var mySubModel = lst.get('mySubModel');

//doesn't work, looks at Runnable.run() not RunnableSubModel.run()
mySubModel.run(); 

However, this doesn't work as I expect.

The id attribute doesn't get set anywhere and only changes if the defaults in Runnable are changed (making it useless!).

The run method on mySubModel calls Runnable.run() from the parent model, not the overwritten run() method in RunableSubModel.

I'm obviously making incorrect assumptions about how inheritance works (or should work) in Backbone, but can't really find any comprehensive explanations.


Answer

The solution was that I was using lst.push([obj]);

This should have been lst.add([obj,obj,..]) or lst.push(obj);.

Backbone was being clever and falling back to the parent object (Runnable)!


Context

I may be going about my task in the wrong way (as this is my first OOP / Backbone js project :D).

I have a one to many mapping between two Collections. The first is a collection of Models representing GUI Checkboxes. Each of these then references one of the Runnable objects. The catch is that multiple Checkboxes can reference the same Runnable instance. In order to do this I have the collection of Runnables (in order to run) and I then want to reference each one by ID when I create my collection of Checkboxes. When Checkbox models are 'checked'/'unchecked' they will notify the Runnable who will in turn notify other listening Checkboxes.

Sidenote

How can I get the 'template' variable to be a global variable between all Runnable sub models?

Thanks

Thank you for reading and any help :).

1

1 Answers

3
votes

You're trying to work directly on the list prototype, RunnableList, when you should be working on an instance (new RunnableList() for example). Try

var lst = new RunnableList();
lst.push(new RunnableSubModel({id: 'mySubModel', alwaysOn: true}));
var mySubModel = lst.get('mySubModel');
mySubModel.run();

And a Fiddle to play with http://jsfiddle.net/NwmHr/1/

Note that you shouldn't set a default id: you probably will get collisions down the line if you create multiple instances without specifying an id (at least when you add them to a collection).

You would use the second argument of extend to add a shared variable, but models having to deal with the DOM is usually considered suspicious.