hguser
hguser

Reputation: 36068

Render Collection model in backbone

Generally when design view for Collection(s), I would bind the collection to the view, and register related events to the collection like this:

var Book = Backbone.Model.extend({});

var BookList = Backbone.Collection.extend({
    model: Book,
    url: "/books"
});

var BookListItemView = Backbone.View.extend({
    mtemplate: _.template($('#tpl_book_item').html()),
    render: function () {
        this.$el = $(this.mtemplate(this.model.toJSON()));
        return this;
    }
});
var BookListView = Backbone.View.extend({
    el: '#content',
    initialize: function () {
        this.listenTo(this.collection, 'add', this.render);
        this.listenTo(this.collection, 'remove', this.render);
    },
    render: function () {
        this.$el.empty();
        this.collection.each(function (item) {
            this.$el.append(new BookListItemView({model: item}).render().$el);
        }, this);
        return this;
    }
});


Use:

    var books = new BookList();
    var bookListView = new BookListView({
        collection: books
    });
    books.fetch();

It worked as expected: render every book as defined in the template. However I found that there is a slight stuck in the page.

I am not sure if this is caused by the re-rendering the view? As shown, when the books.fetch complete, it will add books to the collection of books, for each book item, an add event will be triggered, then I will re-render the page by removing the exist item and iterate the collection.

Which means once there are 10 books, there will be 1+2+3+4...+10 loops for the BookListView.

I my opinion, once the add event triggered, I should not refresh the whole list but just add a new view to the BookListView, but how about the remove event, it seems that Backbone does not provide any internal method to get the view from the model, so once a model to be removed, I can not get the related view.

How do you handle this kind of suitation?

Upvotes: 0

Views: 181

Answers (1)

Exinferis
Exinferis

Reputation: 687

Do not bind your add to the render function. Instead create a dedicated add method for that.

var Book, BookList, BookListItemView, BookListView;

Book = Backbone.Model.extend({});

BookList = Backbone.Collection.extend({
  model: Book,
  url: "/books"
});

BookListItemView = Backbone.View.extend({
  mtemplate: _.template($("#tpl_book_item").html()),
  initialize: function() {
    this.model.on("remove", this.remove);
  },
  render: function() {
    this.$el = $(this.mtemplate(this.model.toJSON()));
    return this;
  }
});

BookListView = Backbone.View.extend({
  el: "#content",
  initialize: function() {
    this.listenTo(this.collection, "add", this.addItem);
  },
  render: function() {
    this.$el.empty();
    this.collection.each((function(item) {
      this.addItem(item);
    }), this);
    return this;
  },
  addItem: function(item) {
    this.$el.append(new BookListItemView({
      model: item
    }).render().$el);
  }
});

Let the models own View handle its own remove event.

Upvotes: 2

Related Questions