我正在制作一个联系栏,用于在html列表中呈现用户的所有联系人。
我有什么:
我目前正在解决一个解决方案,我可以获取我的UserCollection以及如何将单个模型传递给单个ContactView项目。
具体障碍是:
我目前的代码是:
入口点:
// 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;
});
有人可以帮助我解决我的四个障碍。
欢迎良好的示例链接。我在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;
重置是否会触发this.render两次?
答案 0 :(得分:4)
首先:你为什么要获取视图?骨干视图没有fetch方法..
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();
...
}
现在,您可以在需要时准确地获取联系人。下一步是渲染集合。
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方法中呈现您的联系人列表,并在其中完成。
只需使项目在initialize方法中呈现自己,这样就不必在ContactsView的render方法中进行无用的调用,并使代码混乱。也在这里绑定所有。
initialize: function() { // ContactView
_.bindAll(this, 'render', 'otherMethodName', ...);
...
this.render(); // Render in the end of initialize
}
我不知道你在这里问的是什么,但我认为最好的办法就是不要使用成功的回调。集合和模型会在事件发生时触发事件,因此点击它们比成功回调更加强大和可靠。 Check out the catalog of events to learn more. Christophe Coenraets的Wine Cellar tutorial就是这种listview-listitemview安排的一个很好的例子。
希望这有帮助!
更新:添加_.bindAlls以在事件绑定渲染调用中修复此问题。 Some info on binding this.
答案 1 :(得分:2)
注意:所有代码都已简化,未经过测试
如果我已经定义了所有的元素结构,并且实现了所有的模型,集合和视图,那么我实现了一个 Loader ,它负责触发获取和渲染操作。< / p>
首先,我需要从外部公开类定义:
// 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...
然后我实现了我所谓的 Loader :
// 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();
});
您需要做的另一项更改是以响应ContactsView
中的更改的方式配置App.contactsCollection
,因为fetch()
是异步的,您可以调用render()
当集合仍未加载时,您必须告诉CollectionView在集合准备就绪时将其呈现为自我:
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
的外部控制更适合解耦和测试。 注意:如果您使用Router
,则可以将AppLoad.js
逻辑移至那里。