profanis
profanis

Reputation: 2751

how to extend a backbone view

I am new in SPA's with backbone and I am trying to develop a small app by using backbone and requireJs.

The problem I faced is that I can't extend a view by passing a collection.

Well, this is the view with name MenuView.js

define([
'Backbone'
], function (Backbone) {
var MenuView = Backbone.View.extend({
    tagName: 'ul',
    render: function () {
        _(this.collection).each(function (item) {
            this.$el.append(new MenuListView({ model: item }).render().el);
        }, this);
        return this;
    }
});
return new MenuView;
});

and this is the router.js in which the error is appeared

define([
    'Underscore',
    'Backbone',
    'views/menu/menuView',
    'views/createNew/createNew',
    'collections/menu/menuCollection',
], function (_, Backbone, MenuView, CreateNewView,Menucollection) {

var AppRouter = Backbone.Router.extend({
    routes: {
        'index': 'index',
        'action/:Create': 'Create'
    },
    index: function () {
        CreateNewView.clear();
        //-----------  HERE IS THE PROBLEM ------------
        $('#menu').html(MenuView({ collection: Menucollection.models }).render().el);
    },
    Create: function () {
        CreateNewView.render();
    }
});

var initialize = function () {
    var appRouter = new AppRouter();
    Backbone.history.start();
    appRouter.navigate('index', { trigger: true });
};

return {
    initialize: initialize
};
});

The error message is "object is not a function". I agreed with this since the MenuView is not a function. I tried to extend the MenuView (MenuView.extend({collection:Menucollection.models})) and the error message was "objet[object,object] has no method extend".

I suppose that the way I am trying to do this, is far away from the correct one.

Could anyone suggest how to do this?

Thanks

Upvotes: 0

Views: 425

Answers (2)

u.k
u.k

Reputation: 3091

@Matti John's solution will work, but it's more of a workaround than a best practice IMHO.

As it is, you initializing your view just by requiring it, which:

  1. Limits you to never accept arguments
  2. Hits performance
  3. Makes it really hard to unit-test if you relay on assigning properties ater constructing an instance.

A module should be returning a 'class' view and not an instance on that view.

In MenuView.js I would replace return new MenuView with return MenuView; and intitalzie it when required in router.js.

Upvotes: 1

Matti John
Matti John

Reputation: 20477

Your MenuView.js returns an initialized MenuView, so you could just do:

MenuView.collection = Menucollection

Note I haven't selected the models - I think it's better if you don't use the models as a replacement for your view's collection, since it would be confusing to read the code and not have a Backbone collection as the view's collection. You would also lose the method's contained within the collection (e.g. fetch/update).

If you do this, then you would need to update your loop (each is available as a method for the collection):

this.collection.each(function (item) {
            this.$el.append(new MenuListView({ model: item }).render().el);
        }, this);

Upvotes: 0

Related Questions