9

ユーザーのすべての連絡先を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 });

連絡先ビュー:

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;

});

誰かが私の4つのハードルについて私を助けてくれませんか。

良い例のリンクは大歓迎です。私は自分のコードスタイルを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を2回トリガーしている可能性がありますか?

4

2 に答える 2

4

まず第一に、なぜビューをフェッチするのですか?バックボーンビューにはフェッチメソッドがありません。

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

これで、必要なときに連絡先を正確に取得できます。次のステップは、コレクションをレンダリングすることです。

2 resetイベントにバインドすると、loadContactsメソッドが廃止され、render関数で実行できます。

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メソッド内で連絡先リストをレンダリングします。

3ContactViewは実際には見栄えがします。

アイテムを初期化メソッドでレンダリングするだけなので、ContactsViewのrenderメソッドで無駄な呼び出しを行ったり、コードを乱雑にしたりする必要はありません。ここでもbindAll。

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

ここで何を求めているのかわかりませんが、成功のコールバックを使用しないのが最善の方法だと思います。コレクションとモデルは、何かが行われるたびにイベントをトリガーするため、それらをタップすることは、成功のコールバックよりもはるかに堅牢で信頼性があります。詳細については、イベントのカタログをご覧ください。ChristopheCoenraetsによるWineCellarチュートリアルには、この種のlistview-listitemview配置の優れた例があります。

お役に立てれば!

更新:_.bindAllsを追加して、イベントバインドされたレンダリング呼び出しでのこの問題を修正しました。これをバインドするためのいくつかの情報。

于 2012-07-25T10:02:53.330 に答える
2

注:すべてのコードは単純化されており、テストされていません

すべてのモデル、コレクション、およびビューが実装された状態で、すべての要素構造が定義されたら、フェッチおよびレンダリングアクションのトリガーを担当するローダーを実装します。

まず、クラス定義を外部から次のように公開する必要があります。

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

そして、私がローダーと呼ぶものを実装します:

// 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()呼び出すことができるため、コレクションがコレクションのときに自分でレンダリングするようにCollectionViewに指示する必要があるからです。render()準備ができています:

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ファイルを適切な順序で要求する必要があります。

  1. App.js
  2. モデル、コレクション、ビュー
  3. AppLoad.js

このシステムを使用すると、次のものが得られます。

  • 別の場所からコレクションにアクセスする必要がある場合に備えて、コレクションへの外部アクセス。
  • withの外部制御は、CollectionView.elデカップリングとテストに適しています。
  • CollectionViewは、コレクションの変更に自動的に応答します

注:を使用する場合は、ロジックをそこにRouter移動できます。AppLoad.js

于 2012-07-25T10:17:35.073 に答える