How do I render a Backbone Collection in a List and Item View?
我正在使用一个可在html列表中呈现用户所有联系人的联系人栏。
我所拥有的:
我目前正在就如何(在何处)如何获取UserCollection以及如何将单个模型传递给单个ContactView项的解决方案大惊小怪。
具体障碍为:
我当前的代码是这样的:
进入点:
1 2 3 4 5 | // 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 }); |
联系人视图:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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; }); |
有人可以帮我解决我的四个障碍吗。
欢迎使用示例链接。不幸的是,我将代码风格定位在待办事项列表上,但是待办事项列表还不是那么高级...
更新的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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; |
重置是否触发了两次this.render?
首先:为什么要获取视图?Backbone 视图没有获取方法。.
1提取UserCollection的正确位置将在视图的initialize方法内部:
1 2 3 4 5 6 7 | 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(); ... } |
现在,您可以在需要时准确地获取联系人。下一步是呈现集合。
2绑定到reset事件会使您的loadContacts方法过时,我们可以在render函数中做到这一点:
1 2 3 4 5 6 7 8 9 10 11 | 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; } |
现在,您可以在render方法中渲染联系人列表,该操作应该在此完成。
3 ContactView实际上看起来不错。
只需要使该项目在initialize方法中呈现即可,因此您不必在ContactsView的render方法中进行无用的调用,也不会使代码混乱。在这里也请绑定全部。
1 2 3 4 5 | initialize: function() { // ContactView _.bindAll(this, 'render', 'otherMethodName', ...); ... this.render(); // Render in the end of initialize } |
我不知道您在这里要问什么,但我认为最好的方法是不使用成功回调。只要对集合和模型进行了处理,它们就会触发事件,因此,使用它们比成功回调更健壮和可靠。查看事件目录以了解更多信息。 Christophe Coenraets的《酒窖》教程是这种listview-listitemview安排的一个很好的例子。
希望这会有所帮助!
更新:添加了_.bindAlls以解决事件绑定渲染调用中的问题。有关绑定此对象的一些信息。
注意:所有代码均已简化且未经测试
当我定义了所有元素结构并实现了所有模型,集合和视图时,我将实现一个加载器,该加载器负责触发获取和呈现操作。
首先,我需要从外部公开类定义,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // App.js var App = {} // ContactsCollection.js $(function(){ var App.ContactsCollection = Backbone.Collection.extend({ ... }); }); // ContactsView.js $(function(){ var App.ContactsView = Backbone.View.extend({ ... }); }); // and so on... |
然后实现所谓的加载程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // AppLoad.js $(function(){ // instantiate the collection var App.contactsCollection = new App.ContactsCollection(); // instantiate the CollectionView and assign the collection to it var App.contactsView = new App.ContactsView({ el:"div.contacts-body ul", collection: App.contactsCollection }); // fetch the collection the contactsView will // render the content authomatically App.contactsCollection.fetch(); }); |
您需要做的另一项更改是以响应
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | var ContactsView = Backbone.View.extend({ initialize: function( opts ){ this.collection.on( 'reset', this.addAll, this ); this.collection.on( 'add', this.addOne, this ); // ... same with 'remove' }, addOne: function( model ){ var view = new App.ContactView({ model: contact }); this.$el.append( view.render().el ); }, addAll: function(){ this.collection.each( $.proxy( this.addOne, this ) ); } }); |
您必须按正确的顺序要求您的js文件:
使用此系统,您可以获得:
- 外部访问您的收藏集,以防您需要从其他地方访问它。
-
CollectionView.el 的外部控制具有更好的去耦和测试能力。 - CollectionView将自动响应Collection中的更改
注意:如果使用