6

I am trying to write a Backbone view for an object browser which is designed to be implemented in several places with different object types and slightly different operation.

I have tried simply extending the backbone view in my browser and then extending the browser in my implementation however this leaves me with some properties which are shared. This is an undesired effect as the data is appended to all implementations with every browser creation.

Could someone shed light on a way to solve this problem or perhaps an alternative solution?

Here are some code examples to give you a better idea of how it currently stands:

    var BrowserView = Backbone.View;

    _.extend(BrowserView.prototype, Backbone.View.prototype, {
        className: 'browser',

        collections: [],

        events: {

        },

        _events:{

        },

            initialize: function () {
            this._initialize();
        },

        render: function () {
            this._render();
        },

        _initialize: function () {
            this.container = $( this.make('div', {class: 'container'} ) );

            this.$el.append(this.container);

            if ( this.options.collections ) {
                this.collections = [];

                _.each(this.options.collections, this.add, this);
            }

            _.extend(this.events, this._events);

            this.delegateEvents();
        },

        _render: function () {
            this.container.empty();

            _.each(this.collections, function (view) {
                this.container.append(view.el);

                view.render();
            }, this);
        }
    });

    BrowserView.extend = Backbone.View.extend;

    var ContactBrowserView = BrowserView.extend({

    });

EDIT My issue is that the sub classes are sharing the collections property. Here is an example of my own solution which initialises the collections property through an inherited method. jsfiddle.net/JhZXh/3

Eli
  • 369
  • 1
  • 5
  • 12

4 Answers4

11

I think I've figured out the answer to my own problem.

I believe the right way to achieve what I am looking for is to move the initialization of properties in to the initialize method provided by Backbone views. This way they are initialized

var BrowserView = Backbone.View.extend({
    initialize: function () {
        this.collections = [];
    }
});

var FileBrowserView = BrowserView.extend({
    initialize: function () {
        BrowserView.prototype.initialize.apply(this);
        
        this.collections.push({name: 'Example Collection' + Math.rand()});
    }
});


var FileBrowserInstance1 = new FileBrowserView;
console.log(FileBrowserInstance1.collections);

var FileBrowserInstance2 = new FileBrowserView;
console.log(FileBrowserInstance2.collections);

http://jsfiddle.net/yssAT/2/

Eli
  • 369
  • 1
  • 5
  • 12
4

It's hard to see what exactly your goal is.

but this is how i see it if you have an view object

var myView = Backbone.View.extend({
    foo: "bar"
});

and you have it extend the backbone.View... then you actually have a new view object with everything of backbone.view, and the extra options you give as parameters.

if you then go and create a second view, that extends your first one it will get everything from your first view, + it's own extras

var mySecondView = myView.extend({
    foobar: "f00b@r"
});

if you would create an instance of the second view and log it's foo property it will still hold "bar" as value

var mySecondViewInstance = new mySecondView();
console.log("mySecondViewInstance.foo: ", mySecondViewInstance.foo);
console.log("mySecondViewInstance.foobar: ", mySecondViewInstance.foobar);

if i create a new instance of my first view, and change foo into "changed-foo" the log of foo on mySecondViewInstance will still be "bar"

var myViewInstance = new myView();
myViewInstance.foo = "changed-foo";
console.log("mySecondViewInstance.foo: ", mySecondViewInstance.foo);
console.log("mySecondViewInstance.foobar: ", mySecondViewInstance.foobar);

a JS-Fiddle to play around with it can be found here: http://jsfiddle.net/saelfaer/uNBSW/

Sander
  • 13,301
  • 15
  • 72
  • 97
  • Hi Sander, sorry my question wasn't descriptive enough. I have also created a JS-Fiddle to better demonstrate the core of my issue. Perhaps I should've simply done this from the beginning. My issue is that the sub classes are sharing the collections property. http://jsfiddle.net/JhZXh/3/ – Eli Feb 23 '12 at 02:11
  • in any case, just add that jsfiddle and description to your original post, not everyone will find it here in the comment. i'll take a look at it and see if i can come up with a better suitable answer. – Sander Feb 23 '12 at 07:09
3

Inherit from Backbone.View doesn't work, or is quite complex.

You should create a common object, which every of your view will inherit from, ie :

var ViewInterface = {
  events        : { /* ... */ },
  initialize    : function (options) { /* ... */ },
  otherFunction : function (options) { /* ... */ },
}

each of your view would extend from this object :

var BrowserView = Backbone.View.extend(_.extend(ViewInterface, {
  anotherFunction : function (options) { /* ... */ },
})

var AnotherView = Backbone.View.extend(_.extend(ViewInterface, {
  yetAnotherFunction : function (options) { /* ... */ },
})
jney
  • 1,862
  • 2
  • 17
  • 21
  • that would work, but is as far as i know not what the OP needs, his problem was, that instead of `otherFunction`, he defined a property, which was a collection. and by extending from that one view, both the views were sharing the reference to the collection insteaad of having their own collection. that's why he now suggested himself, to initialize it from the initialize method instead of defining it on the view itself. – Sander Feb 24 '12 at 11:09
  • 2
    this does not really work, since extend will copy to ViewInterface, and therefore anotherFunction will also exist in AnotherView. – pedroteixeira Apr 13 '12 at 15:33
2

This gist shows a better alternative: https://gist.github.com/2287018

pedroteixeira
  • 806
  • 7
  • 7