3

これは非常に複雑なものになるため、進行中に追加していきます。

私のアプリは、標準のビューとリージョン (他のビューを含めることのみを目的とした特別なタイプのビュー) の 2 つの主要なビュー タイプから構成されています。 ' 必要に応じて表示します。

アプリのメイン領域 (ヘッダー、フッター、モーダルなど) にあるすべてのビューは、すべて問題なく動作します。今日、他のビュー内にいくつかのサブ領域を作成しようとしましたが、問題が発生しました。何らかの理由でthis.$el.html()、リージョンに割り当てられたビューの出力を渡すためにリージョンを呼び出すと、何も起こりません。コードをステップ実行すると、ビュー自体が適切にレンダリングされ、コンソールでオブジェクト モデルを見るとマークアップを確認できます。ただし、実際にページに結合されることはなく、リージョン ラッパーを表すマークアップしか表示されません。

ここにいくつかのコードがあります-うまくいけば、ある程度の意味をなすでしょうが、これはかなりの数のレベルに落ちます...

まず、ビューとリージョンの基本クラス...

define(['backbone', 'helpers/cookie-manager'],
    function (Backbone, CookieManager) {

        var spinner = "<img src='/content/images/global/ajax-loader.png' alt='loading...' />";        

        var ministryView = Backbone.View.extend({

            name: 'Unnamed View',
            sectionName: 'No section specified',

            stateRequired: false,

            template: undefined,

            bindings: [],

            initialize: function (options) {
                this.options = options || {};
                Backbone.View.prototype.initialize.call(this, options);
                if (this.options.name) {
                    this.name = this.options.name;
                }
                if (this.options.sectionName) {
                    this.sectionName = this.options.sectionName;
                }
                if (this.options.template) {
                    this.template = this.options.template;
                }
            },

            bindToModel: function (model, ev, callback, that) {
                if (that === undefined || that === null) {
                    throw "The value of 'that' needs the context of the extending class in order to operate correctly.";
                }
                model.bind(ev, callback, that);
                this.bindings.push({ model: model, ev: ev, callback: callback });
            },

            dispose: function () {
                this.unbindFromAllModels();   // Will unbind all events this view has bound to
                this.stopListening();
                this.unbind();                // This will unbind all listeners to events from this view. This is probably not necessary because this view will be garbage collected.
                this.remove();                // Uses the default Backbone.View.remove() method which removes this.el from the DOM and removes DOM events.
                this.undelegateEvents();
            },

            render: function () {
                this.trigger('rendered');
                return this;
            },

            resetStyleState: function(condition) {
            },

            trash: function () {
                this.dispose();
            },

            unbindFromAllModels: function () {
                _.each(this.bindings, function (binding) {
                    binding.model.unbind(binding.ev, binding.callback);
                });
                this.bindings = [];
            }
        });

        var ministryRegion = ministryView.extend({

            name: 'Unnamed Region',

            currentView: undefined,

            initialize: function (options) {
                this.options = options || {};
                ministryView.prototype.initialize.call(this, options);
                if (this.options.currentView) {
                    this.currentView = this.options.currentView;
                }
                _.bindAll(this, 'placeRenderedView');
                _.bindAll(this, 'showRendering');
            },

            placeRenderedView: function () {
                this.$el.html(this.currentView.$el);
                this.currentView.delegateEvents();

                if (this.currentView.postRender !== undefined && this.currentView.postRender !== null) {
                    this.currentView.postRender();
                }
            },

            renderView: function (view) {
                if (view) {
                    if (this.currentView) {
                        this.currentView.trash();
                    }

                    this.currentView = view;
                }

                this.currentView.bind('rendering', this.showRendering);
                this.currentView.bind('rendered', this.placeRenderedView);
                this.currentView.render();
            },

            showRendering: function () {
                this.$el.html(spinner);
            },

            trash: function(disposeRegion) {
                this.currentView.trash();

                if (disposeRegion !== undefined && disposeRegion !== null && disposeRegion !== false) {
                    this.dispose();
                }
            }
        });


        return {
            View: ministryView,
            Region: ministryRegion
        };
    });

ビューをロードしたい領域を含むアプリにロードされるビュー ( mealPlansRegion)...

define(['ministry', 'jquery', 'views/v-header', 'models/m-ns', 'views/components/components', 'text!templates/hub/member-home.html'],
    function (Ministry, $, Header, Models, Components, TemplateSource) {    
        var memberHomeView = Ministry.SecureView.extend({

            name: 'Member Home',
            sectionName: 'Hub',

            mealPlansRegion: undefined,

            template: Handlebars.compile(TemplateSource),

            headerView: new Header({ text: 'Kitchen Hub', swatch: 'a' }),

            initialize: function (options) {
                Ministry.SecureView.prototype.initialize.call(this, options);
            },

            // Need to override the normal secured view implementation.
            render: function () {
                this.$el.html(this.template(this));
                this.mealPlansRegion = new Ministry.Region({ el: '.meal-plans-container' });
                this.mealPlansRegion.renderView(new Components.MealPlansList({ collection: new Models.MealPlan.OwnedCollection({ username: App.session.username() }) }));
                this.trigger('rendered');
                return this;
            },

            postRender: function () {
                if (!this.isSecured()) {
                    App.router.navigate('/');
                    App.renderHome(false);
                }
            }
        });

        return memberHomeView;
    });

...そしてそれはテンプレートです...

<section class="meal-plans-container">
</section>

...現時点では、地域のプレースホルダーのみが含まれています。最終的には、これらのいくつかを交換可能なコンテンツとともにここに置くことを意図しています. 最後に、これが私が読み込もうとしているビューです...

define(['ministry', 'jquery', 'models/m-meal-plan', 'text!templates/components/meal-plans-list.html'],
    function(Ministry, $, MealPlan, TemplateSource) {
        var mealPlansListView = Ministry.SecureView.extend({

            name: 'Meal Plans List Component',

            template: Handlebars.compile(TemplateSource),

            render: function () {
                var that = this;

                if (this.isSecured()) {
                    this.collection.on('fetching', function () {
                        that.trigger('rendering');
                    });

                    this.collection.fetch({
                        success: function() {
                            that.bindData();
                            that.trigger('rendered');
                        },
                        error: function(model, xhr) {
                            that.$el.html('Unable to fetch meal plan data');
                            if (console !== undefined && console !== null) {
                                console.log('Fetch Meal Plan failed: ' + xhr.responseText);
                            }
                            that.trigger('rendered');
                        }
                    });
                } else {
                    this.applySecureLoginPrompt();
                }

                return this;
            },

            bindData: function () {
                this.$el.html(this.template({ plans: this.collection.toJSON() }));
            }
        });

        return mealPlansListView;
    });

そしてテンプレです…

<ul id="mealPlansList" class="swatch-listview-b">
    <li class="listview-header">Meal Plans</li>
    {{#each plans}}
    <li><span class="meal-plan-id-holder hidden">{{id}}</span>{{name}}</li>
    {{/each}}
</ul>

この特定のビューでは、共通の地域コードのこの部分が失敗します...

        placeRenderedView: function () {
            this.$el.html(this.currentView.$el);
            this.currentView.delegateEvents();

            if (this.currentView.postRender !== undefined && this.currentView.postRender !== null) {
                this.currentView.postRender();
            }
        },

...そして、this.$el.html(this.currentView.$el);行はまったく何もしません。

他にご不明な点がございましたら、お気軽にお問い合わせください。

4

1 に答える 1

2

この記事 ( Backbone View Nesting ) の助けを借りて、なんとかこれを整理することができました。

memberHomeViewクラスを書き直し、リージョンのインスタンス化をrenderからpostRender関数に移動しました。これにより、テンプレートのレンダリングが完了し、領域が正しくインスタンス化されるようになりました (これがpostRender、最初にメソッドを作成した理由であることが今思い出されました。

これが変更された機能です...

define(['ministry', 'jquery', 'views/v-header', 'models/m-ns', 'views/components/components', 'text!templates/hub/member-home.html'],
    function (Ministry, $, Header, Models, Components, TemplateSource) {    
        var memberHomeView = Ministry.SecureView.extend({

            name: 'Member Home',
            sectionName: 'Hub',

            mealPlansRegion: undefined,

            template: Handlebars.compile(TemplateSource),

            headerView: new Header({ text: 'Kitchen Hub', swatch: 'a' }),

            initialize: function (options) {
                Ministry.SecureView.prototype.initialize.call(this, options);
            },

            // Need to override the normal secured view implementation.
            render: function () {
                this.$el.html(this.template(this));
                this.trigger('rendered');
                return this;
            },

            postRender: function () {
                if (!this.isSecured()) {
                    SiansPlanApp.router.navigate('/');
                    SiansPlanApp.renderHome(false);
                } else {
                    // MOVED THE REGION INSTANTIATION HERE
                    this.mealPlansRegion = new Ministry.Region({ el: '.meal-plans-container' });
                    this.mealPlansRegion.renderView(new Components.MealPlansList({ collection: new Models.MealPlan.OwnedCollection({ username: SiansPlanApp.session.username() }) }));
                }
            }
        });

        return memberHomeView;
    });

簡単な言葉で....


外部マークアップにアタッチする場合は、それを使用するサブビューまたは領域を追加する前に、マークアップがレンダリングされていることを確認してください。


于 2013-08-27T21:33:37.320 に答える