7

ある Ember ルートから別のルートに移行すると、次のエラーが発生します。

Error: Object in path item_delet could not be found or was destroyed.

ルートのrenderTemplateフックでは、次のようなことをたくさん行っています。

this.render('item_delete', { into: 'item_parent', outlet: 'item_delete' });

...そして、親/子テンプレートの合理的なツリーを持っています。ただし、「item_delete」などのテンプレートが「routeA」にレンダリングされ、「routeB」をクリックしてから「routeA」に戻ると、エラーが発生します。メモリ リークを防ぐために、ルーターが「routeA」を終了するときにビュー オブジェクトが破棄されていることを理解しています。ルートを再入力してもビューが再作成/インスタンス化/接続されない理由がわかりません。補足として、エラーが表示された場合、以前にレンダリングされたビューでこのエラー メッセージが表示されると、そのパス名は常に 1 文字短くなります。「item_delete」ではなく「item_delet」に注意してください。

私は grunt-ember-templates を使用して Handlebars テンプレートをコンパイルしているため、JSFiddle を投稿するのは少し難しいです。renderTemplate誰かがこのコードを「目視」して、ルートまたはフックが再インスタンス化/接続/などに失敗している可能性があるという明らかな理由にフラグを立てることができるかどうか疑問に思っています. レンダリングされたテンプレート。ビューが破壊されるのを防ぐためにできる「アクティブ化/非アクティブ化」の魔法はありますか? (そもそもビュー オブジェクトを破棄する意図に反することだとは思いますが、すべての選択肢を喜んで聞きます。)

次のような Ember Route マップがあります。

App.Router.map(function () {

    this.route('index', { path: '/projects' });
    this.resource('items', { path: '/projects/folders' }, function() {
        this.resource('item', { path: '/:item_id' }, function() {
            this.route('file_uploads', { path: '/file_upload' });
        });
    });

});

次のように定義されたルートがあります。

App.IndexRoute = Ember.Route.extend({
    redirect: function() {
        this.transitionTo('items');
    }
});

App.ItemsIndexRoute = Ember.Route.extend({

    model: function() {
        // Setting up the model
    }
    , setupController: function(controller, model) {
        // Setting up some controllers
    }
    , renderTemplate: function() {
        this.render('index', {
            into: 'application'
            , outlet: 'application'
            , controller: this.controllerFor('items')
        });

        this.render('navbar', {
            into: 'application'
            , outlet: 'navbar'
            , controller: this.controllerFor('currentUser')
        });

        this.render('items', {
            into: 'index'
            , outlet: 'index'
            , controller: this.controllerFor('items')
        });

        this.render('items_toolbar', {
            into: 'index'
            , outlet: 'items_toolbar'
            , controller: this.controllerFor('items')
        });

        this.render('item_rename', {
            into: 'items_toolbar'
            , outlet: 'item_rename'
            , controller: this.controllerFor('items')
        });

        this.render('item_delete', {
            into: 'items_toolbar'
            , outlet: 'item_delete'
            , controller: this.controllerFor('items')
        });

        // ... some more of these...

    }

});

App.ItemRoute = Ember.Route.extend({

    model: function (params) {
        // Building the model for the route
    }
    , setupController: function(controller, model) {
        // Setting up some controllers
    }
    , renderTemplate: function() {
        this.render('index', {
            into: 'application'
            , outlet: 'application'
            , controller: this.controllerFor('items')
        });

        this.render('navbar', {
            outlet: 'navbar'
            , into: 'application'
            , controller: this.controllerFor('application')
        });

        this.render('items', {
            into: 'index'
            , outlet: 'index'
            , controller: this.controllerFor('items')
        });

        this.render('items_toolbar', {
            into: 'index'
            , outlet: 'items_toolbar'
            , controller: this.controllerFor('items')
        });

        this.render('item_rename', {
            into: 'items_toolbar'
            , outlet: 'item_rename'
            , controller: this.controllerFor('items')
        });

        this.render('item_delete', {
            into: 'items_toolbar'
            , outlet: 'item_delete'
            , controller: this.controllerFor('items')
        });

        // ... some more of these...

    }

});

App.ItemFileUploadsRoute = Ember.Route.extend({

    model: function() {
        // Setting up the model
    }

    , setupController: function(controller, model) {
        // Setting up some controllers
    }

    , renderTemplate: function() {

        this.render('file_uploads', {
            into: 'application'
            , outlet: 'application'
            , controller: this.controllerFor('fileUploads')
        });

        this.render('navbar', {
            into: 'application'
            , outlet: 'navbar'
            , controller: this.controllerFor('application')
        });

        this.render('items_toolbar', {
            into: 'file_uploads'
            , outlet: 'items_toolbar'
            , controller: this.controllerFor('fileUploads')
        });

        this.render('item_rename', {
            into: 'items_toolbar'
            , outlet: 'item_rename'
            , controller: this.controllerFor('items')
        });

        this.render('item_delete', {
            into: 'items_toolbar'
            , outlet: 'item_delete'
            , controller: this.controllerFor('items')
        });

        // ... some more of these...
    }

});

いくつかのテンプレートとそのアウトレットをさまざまなルート/リソースに再利用しています。たとえば、上記の「items_toolbar」は、次のようなハンドルバー テンプレートにあります。

<div class="row toolbar">
    <div class="col col-lg-6 text-right">
        {{outlet submission_options_button}}
        {{outlet submission_button}}
        {{outlet create_button}}
        {{outlet confirm_button}}
        {{outlet cancel_button}}
        {{outlet folder_actions}}
        {{outlet item_rename}}
        {{outlet item_delete}}
    </div>
</div>

このテンプレートでは、すべてのアウトレットがレンダリングされたバッファを取得するわけではなく、他のコンテキストでは取得されます。これは、Handlebars コードの望ましくない (紛らわしい) 条件 (および通常の「isVisible」ナンセンス) を避けるために行っています。必要に応じてそのビューを「身に着けている」特定のテンプレートに興味があります。「create_button」と「cancel_button」がある場合もあれば、「cancel_button」と「folder_actions」がある場合もあります。

ルートに再び入るときに、以前にレンダリングされてから破棄されたオブジェクトを再接続、再初期化、および/または再レンダリングできるようにする確実な方法はありますか?

4

2 に答える 2

3

興味のある方はこの続きをどうぞ。私のアプローチでの(過剰な)使用は{{outlet}}、ルーター内でテンプレートをそれらにレンダリングすることは言うまでもありませんが、アンチパターンであることがわかりました。

Tilde のギャング (@peterwagenet、@codeofficer に感謝) と何度も議論した後、私がしようとしていることを行うための「Ember Way」は、Ember が提供する生成されたルートとコントローラーを使用し、{{view}}ヘルパーを使用してHandlebars テンプレート内のビュー オブジェクトを直接レンダリングします。

したがって、上記の私の場合、 にはほとんど何もなく、テンプレートには s がまったくないはずApp.ItemsIndexRoute.renderTemplate()です{{outlet}}。名前付き{{outlets}}は、現在のルートの「外側」にあるルートをレンダリングするためのものです。標準的な例は、アウトレットがレンダリングされている親ルートとは異なるモデルを持つモーダルです。例えば:

<div>
    {{view App.UsersListView}}
    {{outlet order_books_from_mars_modal}}
</div>

私が持っていたルートはApp.Router.map()ほとんど正しいですが、生成されたコントローラーに関していくつかの大きな誤解があります。がある場合、Emberはアプリケーション コードのどこかに定義する必要がある をApp.FooRoute設定します。次のように、ルートのフックで指定したものをモデルとして持つApp.FooControllerことができます。App.FooControllermodel

App.FooRoute = Ember.Route.extend({

    model: function() {
        return $.get('/some/resource', function() { ... });
    }

});

そして、 内でレンダリングされるすべてのビューに与えられるコントローラーApp.FooRouteApp.FooController、以前にルートのmodelフックで提供されたモデルを持っています。

Ember.Viewそしてルーターは、ルートとコントローラーのプレフィックスに一致するオブジェクトを探しますApp.FooView。したがって、次のような場合:

App.FooView = Ember.View.extend({

    template: 'some-foo-template'

});

... に一致するルートはApp.FooControllerをレンダリングApp.FooViewし、ビューのtemplateプロパティで指定されたテンプレートをレンダリングします。何かのようなもの:

<script type="text/x-handlebars" data-template-name="some-foo-template">
    <div class="row toolbar">
        <div class="col col-lg-6 text-right">
            {{view App.SubmissionButtonView}}
        </div>
    </div>
</script>

このビューでは、ヘルパーApp.SubmissionButtonViewを使用して がレンダリングされています。{{view}}したがって、対応する必要があります。

App.SubmissionButtonView = Ember.View.extend({

    template: 'the-killer-button'

});

... テンプレートは次のようになります。

<script type="text/x-handlebars" data-template-name="the-killer-button">
    <a {{action someControllerMethod}}>Do Something</a>
</script>

someControllerMethodにあると予想されますApp.FooController。コントローラで見つからない場合、アクションはApp.FooRouteeventsオブジェクトにバブルアップされます。チェーンのどのオブジェクトにもメソッドが見つからない場合、アクションを処理したものがないことを示すエラーがログに記録されますsomeControllerMethod

その結果、 は内でレンダリングされるため、デフォルトで にApp.FooController提供されるものになります。ただし、次のようにして、別のコントローラーをバインドすることができます。App.SubmissionButtonViewApp.FooRouteApp.BarController

{{view App.SubmissionButtonView controllerBinding='App.BarController'}}

この場合、それは、または前述someControllerMethodの で見つかることが期待されます。App.BarControllerApp.FooRoute

レッスン?

これらすべての最後に、私にとっての教訓は、ルート階層を適切に確立し、Ember が提供する生成されたコントローラーを利用し、最初に試み{{view}}た名前付き s ではなくヘルパーを使用してビューをレンダリングすることでした。{{outlet}}Ember は、名前付きルートに対応するコントローラーと対応するビューがあることを期待しています。これを理解すると、すべてがうまくまとまり始めました。

私の場合、ネストされたリソースはすべて子ビューのレンダリングを適切に処理するため、ユーザーが現在のルートから「離れて」ナビゲートするとそれらを破棄し、ユーザーが現在のリソース/ルートの「内」をナビゲートするときにそれらを保持します-私が投稿した元のエラーは発生しなくなりました。

いつものように、愚かな自分を Embering するための最良のリソースはEmber Guidesです。

于 2013-09-20T06:04:26.847 に答える