How do I render a Backbone Collection in a List and Item View?

Viewed 12417

I am working on a contact bar which renders all contacts of a user in a html list.

What I have:

  1. UserModel - This is a simple Backbone.Model with username and email
  2. UserCollection - This is used as the contact list
  3. ContactsView - This is the ul contact list
  4. ContactView - This is a single contact model rendered as li

I am currently breaking my head about a solution how (and where) I can fetch my UserCollection and how I pass the single models down to a single ContactView item.

Specific hurdles are:

  1. Where should I fetch, store the UserCollection
  2. How do I render the contact list
  3. How do I render the contact items
  4. How do I prevent fetch({ success: callback }) from breaking my code structure

My current code is this:

entrance point:

// create a new instance of the contact list view
var view = new ContactsView();
// insert the rendered element of the contact list view in to the dom
$('div.contacts-body').html(view.render().el);
view.fetch({ success: view.loadContacts });

ContactsView:

define(
    ['jquery', 'underscore', 'backbone', 'text!templates/conversations/contacts.html', 'collections/users', 'views/conversations/contact'],
    function($, _, Backbone, ContactsTemplate, UserCollection, ContactView) {

        var ContactsView = Backbone.View.extend({

            tagName: "ul",

            className: "contacts unstyled",

            attributes: "",

            // I am feeling uneasy hardcoding the collection into the view
            initialize: function() {
                this.collection = new UserCollection();
            },

            // this renders our contact list
            // we don't need any template because we just have <ul class="contacts"></ul>
            render: function() {
                this.$el.html();
                return this;
            },

            // this should render the contact list
            // really crappy and unflexible
            loadContacts: function() {
                this.collection.each(function(contact) {
                    // create a new contact item, insert the model
                    var view = new ContactView({ model: contact });
                    // append it to our list
                    this.$el.append(view.render().el);
                });
            }

        });

        return ContactsView;

});

ContactView

define(
    ['jquery', 'underscore', 'backbone', 'text!templates/conversations/contact.html'],
    function($, _, Backbone, ContactTemplate) {

        var ContactView = Backbone.View.extend({

            tagName: "li",

            className: "contact",

            attributes: "",

            template:_.template(ContactTemplate),

            initialize: function() {
                this.model.bind('change', this.render, this);
                this.model.bind('destroy', this.remove, this);
            },

            render: function() {
                this.$el.html(this.template(this.model.toJSON()));
                return this;
            }

        });

        return ContactView;

});

Could somebody help me about my four hurdles.

Good example links are welcome. I oriented my code style at the todos list unfortunatly the todos list isn't that advanced...

UPDATED CODE:

define(
    ['jquery', 'underscore', 'backbone', 'text!templates/conversations/contacts.html', 'collections/users', 'views/conversations/contact'],
    function($, _, Backbone, ContactsTemplate, UserCollection, ContactView) {

        var ContactsView = Backbone.View.extend({

            tagName: "ul",

            className: "contacts unstyled",

            attributes: "",

            events: {

            },

            initialize: function() {
                this.collection = new UserCollection();
                this.collection.on('reset', this.render);
                this.collection.fetch();
            },

            render: function() {
                // in chromium console
                console.log(this.el); // first: html, second: undefined
                console.log(this.$el); // first: html in array, second: undefined
                this.$el.empty(); // error on the called that this.$el is undefined

                this.collection.each(function(contact) {
                    var view = new ContactView({ model: contact });
                    this.$el.append(view.el);
                }.bind(this));

                return this;
            }

        });

        return ContactsView;

Can it be that reset is triggering this.render twice?

2 Answers
Related