如何在列表和项目视图中呈现Backbone集合?

bod*_*ser 9 javascript backbone.js

我正在开发一个联系栏,用于在html列表中呈现用户的所有联系人.

是)我有的:

  1. UserModel - 这是一个简单的Backbone.Model,包含用户名和电子邮件
  2. UserCollection - 用作联系人列表
  3. ContactsView - 这是ul联系人列表
  4. ContactView - 这是一个呈现为li的单一联系人模型

我目前正在解决一个解决方案,我如何(以及在​​哪里)获取我的UserCollection以及如何将单个模型传递给单个ContactView项目.

具体障碍是:

  1. 我应该在哪里获取,存储UserCollection
  2. 如何呈现联系人列表
  3. 如何呈现联系人项目
  4. 如何防止fetch({success:callback})破坏我的代码结构

我目前的代码是这样的:

入口点:

// 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 });
Run Code Online (Sandbox Code Playgroud)

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;

});
Run Code Online (Sandbox Code Playgroud)

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;

});
Run Code Online (Sandbox Code Playgroud)

有人可以帮助我解决我的四个障碍.

欢迎提供良好的示例链接.我在todos列表中定位了我的代码风格,不幸的是todos列表不是那么高级...

更新的代码:

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;
Run Code Online (Sandbox Code Playgroud)

重置是否可以触发this.render两次?

jak*_*kee 4

首先:为什么要获取视图?主干视图没有 fetch 方法。

1 获取 UserCollection 的正确位置是在视图的初始化方法中:

initialize: function() { // ContactsView
  _.bindAll(this, 'render', 'otherMethodName', ...); // Bind this to all view functions
  ...
  this.collection.on('reset', this.render); // bind the collection reset event to render this view
  this.collection.fetch();
  ...
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以在需要时准确地获取联系人。下一步是渲染集合。

2 绑定到重置事件会使您的 loadContacts 方法过时,我们可以在渲染函数中做到这一点:

render: function() {
  this.$el.empty(); // clear the element to make sure you don't double your contact view
  var self = this; // so you can use this inside the each function

  this.collection.each(function(contact) { // iterate through the collection
    var contactView = new ContactView({model: contact}); 
    self.$el.append(contactView.el);
  });

  return this;
}
Run Code Online (Sandbox Code Playgroud)

现在,您在渲染方法中渲染联系人列表,这是应该完成的。

3 ContactView 实际上看起来不错。

只需让项目在初始化方法中呈现自身,这样您就不必在 ContactsView 的呈现方法中进行无用的调用并弄乱您的代码。也在这里bindAll。

initialize: function() { // ContactView
  _.bindAll(this, 'render', 'otherMethodName', ...);
  ...
  this.render(); // Render in the end of initialize
}
Run Code Online (Sandbox Code Playgroud)

我不知道你在这里问什么,但我认为最好的方法是不要使用成功回调。每当对集合和模型执行某些操作时,集合和模型就会触发事件,因此利用它们比成功回调更加强大和可靠。查看活动目录以了解更多信息。Christophe Coenraets 的Wine Cellar 教程提供了这种列表视图-列表项目视图排列的绝佳示例。

希望这可以帮助!

更新:添加 _.bindAlls 以修复事件绑定渲染调用中的问题。有关绑定此内容的一些信息。