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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11646402/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 13:54:18  来源:igfitidea点击:

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

javascriptbackbone.js

提问by bodokaiser

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

我正在处理一个联系人栏,它在 html 列表中呈现用户的所有联系人。

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
  1. UserModel - 这是一个带有用户名和电子邮件的简单 Backbone.Model
  2. UserCollection - 这用作联系人列表
  3. ContactsView - 这是 ul 联系人列表
  4. ContactView - 这是呈现为 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.

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

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

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?

是不是重置会触发 this.render 两次?

采纳答案by jakee

First of all: why do you fetch the view? Backbone views do not have a fetch method..

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

1 The correct place to fetch your UserCollection would be inside the view's initialize method:

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

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();
  ...
}

Now you fetch the contacts exactly when you need them. Next step is to render the collection.

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

2 Binding to the reset event makes your loadContacts method obsolete and we can do that in the render function:

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;
}

Now you render your contactlist inside the render method, where it should be done.

现在你在渲染方法中渲染你的联系人列表,它应该在那里完成。

3 The ContactView actually looks good.

3 ContactView 实际上看起来不错。

Just make the item to render itself in the initialize method, so you don't have to make useless calls in the ContactsView's render method and clutter up your code. Also bindAll here as well.

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

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

I have no idea what you are asking in here, but I think the best way is not to use success callbacks. The collections and models trigger events whenever something is done to them, so tapping onto them is much more robust and reliable than success callbacks. Check out the catalog of events to learn more.The Wine Cellar tutorialby Christophe Coenraets is has an excellent example of this kind of listview-listitemview arrangement.

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

Hope this helps!

希望这可以帮助!

UPDATE: Added _.bindAlls to fix the problem with this in a event bound render call. Some info on binding this.

更新:添加 _.bindAlls 以解决事件绑定渲染调用中的问题。关于绑定这个的一些信息。

回答by fguillen

NOTE: all the code is simplified and no tested

注意:所有代码都经过简化且未经测试

When I have all the elements structure defined, as you have, with all the Models, Collections and Views implemented then I implement a Loaderwhich is in charge of trigger the fetching and rendering actions.

当我像你一样定义了所有的元素结构,并实现了所有的模型、集合和视图,然后我实现了一个加载器,它负责触发获取和呈现操作。

First of all I need to expose the classes definition from the outside something like this:

首先,我需要从外部公开类定义,如下所示:

// 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...

And then I implement what I call the Loader:

然后我实现了我所说的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();
});

Another changes you have to do is configure the ContactsViewin a way that respond to the changes in the App.contactsCollectionbecause as the fetch()is asynchronous you can call render()when the collection is still not loaded, so you have to tell to the CollectionView to render it self when the Collection is ready:

您必须做的另一项更改是以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 ) );
  }
});

You have to requireyour js files in the proper order:

你必须以正确的顺序要求你的 js 文件:

  1. App.js
  2. Your Models, Collections, Views
  3. AppLoad.js
  1. 应用程序.js
  2. 您的模型、集合、视图
  3. 应用加载.js

With this system you obtain:

使用此系统,您将获得:

  • External access to your collection in case you need to access it from another place.
  • External control of the CollectionView.elwith is better for decoupling and testing.
  • The CollectionView will respond to changes in the Collection authomatically
  • 外部访问您的收藏,以防您需要从其他地方访问它。
  • 与外部控制CollectionView.el更好的解耦和测试。
  • CollectionView 将自动响应 Collection 中的更改

Note:If you use Routeryou can move the AppLoad.jslogic to there.

注意:如果您使用,Router您可以将AppLoad.js逻辑移到那里。