1

短いバージョン:属性の1つとして2番目のBackboneモデルを持つBackboneモデルがあります。最初のモデルの関数は2番目のモデルの状態を変更しますが、最初のモデルへの変更をリッスンしている私のビューは、そうでないことを示唆するログの量にもかかわらず、2番目のモデルの状態を取得していないようです(thisスコープなどを確認するために、さまざまなポイントでログを記録しています )。どうすればこれを修正できますか?

長いバージョンCourse:アカデミックコースを表すBackboneモデルと、NameListに登録されている学生のリストを表すモデルがありCourseます。「Coursehas-a」NameList。ANameListは、サーバー上の単一のテキストファイルによってバックアップされます。

Courseと呼ばれるモデルにimportNameList、新しいNameListモデルを作成し、そのNameListモデルとfetchそのデータをバックエンドから取得させる関数が必要です。私のビューはモデルCourseViewへの変更をリッスンしており、モデルには-aがあるので、それに応じてビューを更新する必要があるようです。私の問題はそうではないということです。CourseCourseNameList

私がやりたいこと

var course = new Course();
var courseView = new CourseView({model : course});
courseView.model.importNameList('students.txt'); // Will cause view to re-render

私がしなければならないこと

var course = new Course(); // same 
var courseView = new CourseView({model : course}); // same
courseView.model.importNameList('students.txt'); // same
courseView.render(); // Argh, manually calling this is ugly.

これがロギングステートメントを含む私のコードです。モデルが拡張Backbone.DeepModelされるのは、問題が解決するかもしれないと思ったからですが、そうではありませんでした。

コンソール出力

[console] var course = new Course();
[console] var courseView = new CourseView({model : course});
[console] course.importNameList('students.txt');

          Course >>> importNameList
          NameList >>> initialize()
          NameList >>> fetch()
          GET http://localhost/files/students.txt 200 OK 16ms    
          CourseView >>> render() // Render starts before fetch completes
          CourseView <<< render() // Render finishes before fetch completes
          Course <<< importNameList
          NameList <<< fetch()

[console] courseView.render();

          CourseView >>> render()
          alice
          bob
          charlie
          dan
          erica
          fred
          george
          CourseView <<< render()

Course.js

var Course = Backbone.DeepModel.extend({

    defaults : {
        nameList : new NameList()
    },

    initialize: function(options) {

        if (options && options.nameList) {
            this.set({nameList : options.nameList});
        }

    },

    importNameList : function(fileName) {

        console.log("Course >>> importNameList");
        var nameList = new NameList({fileName : fileName});
        this.set({nameList : nameList});
        console.log("Course <<< importNameList");
    }
});

NameList.js

var NameList = Backbone.DeepModel.extend({

    defaults : {
        fileName : 'new.txt',
        names : []
    },

    initialize: function(options) {

        console.log("NameList >>> initialize()");
        var model = this;

        if (options && options.fileName) {
            model.set({fileName : options.fileName});
        }
        model.fetch();
    },

    fetch : function() {
        console.log("NameList >>> fetch()");
        var model = this;
        $.ajax({
            url : '/files/' + model.get('fileName'),
            success : function(response) {
                model.set({names : response.split('\n')});
                console.log("NameList <<< fetch()");
            }
        });
    }
});

CourseView.js

var CourseView = Backbone.View.extend({

    initialize : function(options) {

        var view = this;
        if (options && options.model) {
            view.model = options.model;
        } else {
            view.model = new Course();
        }

        view.model.on('change', function() {
            view.render();
        });

    },

    render : function() {

        console.log("CourseView >>> render()");
        var names = this.model.get('nameList').get('names');
        for (var i = 0; i < names.length; i++) {
            console.log(names[i]);
        }
        console.log("CourseView <<< render()");
        return this;
    }

});
4

2 に答える 2

0

私は最終的に次のことをしました。

CourseView.js:

// No changes.

Course.js 内:

importNameList : function(name) {

    var model = this;
    var nameList = new NameList({fileName : fileName});
    // Set the attribute silently (without triggering a change event)
    model.set({nameList : nameList}, {silent: true});
    nameList.fetch({
        success : function() {
            model.change(); // Manually fire a change event when fetch completes.
        }
    });
}

NameList.js 内:

fetch : function(options) {
    var model = this;
    $.ajax({
        url : '/files/' + model.get('fileName'),
        success : function(response) {
            model.set({lines : response.split('\n')});
            // Make the "success" callback.
            options.success();
        }
    });
}
于 2012-09-03T02:51:06.233 に答える
0

簡単な答えは、deferredオブジェクトとして jQuery を使用することです。この記事では、backbone.js で deferred を使用する方法について詳しく説明します。

より具体的な情報を追加しますが、フェッチをオーバーライドしている理由がよくわかりません。これは災害のレシピのようです。バックボーンの元の fetch メソッドに固執し、NameList の初期化子から除外し、代わりに Course.js から呼び出し、そこから返された deferred を使用して、フェッチが完了したら次のステップが実行されることを保証します。

アップデート:

これを行う 1 つの方法のスケッチを次に示します。最初にのメソッドmodel.fetch();から行を取り出し、その戻り値 (遅延オブジェクト) を の戻り値として使用して、代わりに で呼び出します。initializeNameListimportNameListimportNameList

var nameList = new NameList({fileName : fileName});
this.set({nameList : nameList});
return nameList.fetch()

deferred from を返すimportNameListようになったので、これを使用して、レンダリング前にフェッチが完了していることを保証できます。

this.deferred = courseView.model.importNameList('students.txt');
this.deferred.done(function() { courseView.render() });

私は実際にテストしていませんが、それはあなたが望むことをするべきだと思います。

于 2012-08-26T03:36:57.327 に答える