1

私の問題の簡単な要約: ビューの最初のレンダリングにはコレクション内の要素が含まれていますが、2 番目のレンダリングには含まれていません。詳しくは続きを読む...

また、注意: 次のコードはハッピー パスを表しており、潜在的なエラー処理コードが欠落している可能性がたくさんあることを認識しています。これは簡潔にするために意図的に行われています。

私は backbone.js にかなり慣れていないため、次のシナリオのソリューションを実装する正しい方法を見つけるのに苦労しています。

アプリケーションのメイン レイアウトとなるレンダリングされたコンテンツを格納/表示するために、2 つのメイン リージョンでシェル化されたページがあります。一般に、次のようになります。

-------------------------------------------
|                          |              |
|                          |              |
|         Content          |   Actions    |
|          Panel           |    Panel     |
|                          |              |
|                          |              |
|                          |              |
|                          |              |
|                          |              |
|                          |              |
-------------------------------------------

私は、データを取得している HTTP API を持っています。これは、実際には、さまざまなモジュールのリソース情報を、OPTIONS各モジュールのベース URL への呼び出しからの JSON 結果の形式で提供します。たとえば、次のようなOPTIONSリクエストをhttp://my/api/donor-corps返します。

[
    {
        "Id":0,
        "Name":"GetDonorCorps",
        "Label":"Get Donor Corps",
        "HelpText":"Returns a list of Donor Corps",
        "HttpMethod":"GET",
        "Url":"https://my/api/donor-corps",
        "MimeType":"application/json",
        "Resources":null
    }
]

アプリケーションには、私が呼び出しているバックボーン コレクションがあります。これは、複数の異なるバックボーン ビューによってレンダリングされ、アプリケーションの異なるページに異なる方法で表示される可能性のあるオブジェクトDonorCorpsCollectionの読み取り専用コレクションになります (最終的には...後で.. DonorCorpModel.現時点ではそうではありません)。のurlプロパティは、API モジュール リソースを取得するための最初の呼び出しの結果の「GetDonorCorps」プロパティを持つオブジェクトDonorCorpsCollectionのプロパティである必要があります (上記を参照)。UrlNameOPTIONS

アプリケーションには上部にメニューバーがあり、クリックするとアプリのさまざまなページが表示されるリンクがあります。今のところ、アプリには「ホーム」ページと「プレソート」ページの 2 つのページしかありません。「ホーム」ビューでは、両方のパネルにプレースホルダー情報が含まれているだけで、ユーザーがメニュー バーのリンクをクリックして実行するアクションを選択する必要があることを示しています。DonorCorpsCollectionユーザーが「並べ替え前」ページのリンクをクリックすると、アクション パネルに順序付けされていないリストとしてレンダリングするバックボーン ビューを表示したいだけです。

私は現在、アプリケーション コードを整理してカプセル化するためにJavaScript モジュール パターンを使用しています。現在、私のモジュールは次のようになっています。

var myModule = (function () {

// Models
    var DonorCorpModel = Backbone.Model.extend({ });

// Collections
    var DonorCorpsCollection = Backbone.Collection.extend({ model : DonorCorpModel });

// Views
    var DonorCorpsListView = Backbone.View.extend({
        initialize : function () {
            _.bindAll(this, 'render');
            this.template = _.template($('#pre-sort-actions-template').html());
            this.collection.bind('reset', this.render); // the collection is read-only and should never change, is this even necessary??
        },

        render : function () {
            $(this.el).html(this.template({})); // not even exactly sure why, but this doesn't feel quite right

            this.collection.each(function (donorCorp) {
                var donorCorpBinView = new DonorCorpBinView({
                    model : donorCorp,
                    list : this.collection
                });

                this.$('.donor-corp-bins').append(donorCorpBinView.render().el);
            });

            return this;            
        }
    });

    var DonorCorpListItemView = Backbone.View.extend({
        tagName : 'li',
        className : 'donor-corp-bin',

        initialize : function () {
            _.bindAll(this, 'render');
            this.template = _.template($('#pre-sort-actions-donor-corp-bin-view-template').html());
            this.collection.bind('reset', this.render);
        },

        render : function () {
            var content = this.template(this.model.toJSON());
            $(this.el).html(content);
            return this;
        }
    });

// Routing
    var App = Backbone.Router.extend({
        routes : {
            '' : 'home',
            'pre-sort', 'preSort'
        },

        initialize : function () { },

        home : function () {
            // ...
        },

        preSort : function () {
            // what should this look like??
            // I currently have something like...

            if (donorCorps.length < 1) {
                donorCorps.url = _.find(donorCorpResources, function (dc) { return dc.Name === "GetDonorCorps"; }).Url;
                donorCorps.fetch();
            }

            $('#action-panel').empty().append(donorCorpsList.render().el);
        }
    })

// Private members
    var donorCorpResources;
    var donorCorps = new DonorCorpsCollection();
    var donorCorpsList = new DonorCorpsListView({ collection : donorCorps });

// Public operations
    return {
        Init: function () { return init(); }
    };

// Private operations
    function init () {
        getAppResources();
    }

    function getAppResources () {
        $.ajax({
            url: apiUrl + '/donor-corps',
            type: 'OPTIONS',
            contentType: 'application/json; charset=utf-8',
            success: function (results) {
                donorCorpResources = results;
            }
        });
    }

}(myModule || {}));

最後に、これはすべて次の HTML を使用しています。

...
<div class="row-fluid">
    <div id="viewer" class="span8">
    </div>
    <div id="action-panel" class="span4">
    </div>
</div>
...
<script id="pre-sort-actions-template" type="text/template">
    <h2>Donor Corps</h2>
    <ul class="donor-corp-bins"></ul>
</script>

<script id="pre-sort-actions-donor-corp-bin-view-template" type="text/template">
    <div class="name"><%= Name %></div>
</script>

<script>
    $(function () {
        myModule.Init();
    });
</script>
...

これまでのところ、 「事前並べ替え」メニュー リンクを初めてクリックしたときに、これを機能させることができました。クリックすると、Donor Corps のリストが期待どおりに表示されます。しかし、[ホーム] リンクをクリックしてから、[事前並べ替え] リンクをクリックすると、今度はヘッダーが<ul class="donor-corp-bins"></ul>表示されますが、リスト項目がなく空です。...そして、なぜ、または何を別の方法で行う必要があるのか​​ わかりません。backbone.js の Views と Routers は一般的に理解しているように感じますが、実際には何かが足りないようです。

一般的に、これはかなり単純なシナリオのように思えます。ここで何か例外的なことをしようとしているような気がしませんが、正しく動作させることができず、その理由を理解できないようです. アシスト、または少なくとも正しい方向へのナッジは、非常に高く評価されます。

4

2 に答える 2

1

DonorCorpListViewのレンダリングコードは私には奇妙に見えます-データを取得する前にテンプレートを作成しているように見えます。HTML出力を取得するには、そのテンプレートデータとともにコンパイルする必要があります。

したがって、レンダリングロジックは次のようになります。

var template = $([get the template).html();
template.compile(this.collection.toJSON());
this.el.append(template.render());

テンプレートメカニズムがわからないため、ここではいくつかの擬似コードを使用しました(私はハンドルバーが好きです)。

于 2012-06-28T20:47:59.367 に答える
1

だから、私はここで解決策を見つけました。それが最善の解決策か正しい解決策かはわかりませんが、少なくとも今のところは機能します。

いくつかの問題があったようです。Rob Conery のフィードバックに基づいて、ビュー テンプレートでコレクションをレンダリングするためのさまざまなオプションを検討し始めました。これが私が思いついたものです。

コメントで述べたように、ビューのテンプレート化にハンドルバーを使用しているため、このコードではそれを使用しています。

ビューテンプレートを次のように変更しました。

<script id="pre-sort-actions-template" type="text/x-handlebars-template">
    <h2>Donor Corps</h2>
    <ul class="donor-corp-bins">
    {{#each list-items}}
        <li class="donor-corp-bin">{{this.Name}}</li>
    {{/each}}
    </ul>
</script>

DonorCorpListItemView次に、完全に削除し、次のDonorCorpsListViewように変更しました。

var DonorCorpsListView = Backbone.View.extend({
    initialize : function () {
        _.bindAll(this, 'render');
        this.collection.bind('reset', this.render);
    },
    render : function () {
        var data = { 'list-items' : this.collection.toJSON() };
        var template = Handlebars.compile($('#pre-sort-actions-template').html());
        var content = template(data);
        $(this.el).html(content);

        return this;
    }
});

それで、それは機能しているようで、今必要なことをやっているようです。

ただし、JS と Backbone.js がどのように機能するかについては、まだ多くのことを学ぶ必要があることは明らかです。なぜなら、次のコードは機能しない(エラーが発生する) ためです...そして、その理由がわかりません。

var DonorCorpsListView = Backbone.View.extend({
    initialize : function () {
        _.bindAll(this, 'render');
        this.template = Handlebars.compile($('#pre-sort-actions-template').html());
        this.collection.bind('reset', this.render);
    },
    render : function () {
        var data = { 'list-items' : this.collection.toJSON() };
        var content = this.template(data);
        $(this.el).html(content);

        return this;
    }
});

うまくいけば、これは誰かに役立つでしょう。

于 2012-06-29T19:07:29.913 に答える