3

インデックス関数をレンダリングしようとするとエラーが発生するのはなぜだろうと思いcannot call method render of nullます。ルーターの初期化が完了するまで、インデックス関数のレンダリングを待機させる方法はありますか?console.logsは、初期化でajax呼び出しが行われる前にインデックス関数がレンダリングしようとしていることを示唆しているようです

1.Uncaught TypeError: Cannot call method 'render' of null gallery.js:231
2. XHR finished loading: "http://localhost:3000/readjsonfile". jquery.js:8241
3.success 

これがコードです。ルートがあります

var Gallery = Backbone.Router.extend({

routes: {
        "": "index",

    },

最初はnullに設定されています

 _index: null,

Galleryルーターの初期化では、インデックスがnullかどうかがチェックされ、nullの場合は、データを含む新しいビューが作成されます。

initialize: function(options) {

        var ws = this;

        if (this._index === null){
            $.ajax({

                url: 'galleries',
                dataType: 'json',
                data: {},
                success: function(data) {
                    console.log("success");
                    console.log(data);
                    ws._data = data;
                    ws._photos = new PhotoCollection(data);
                    ws._index = new IndexView({model: ws._photos});
                    console.log(ws._index);

                    Backbone.history.loadUrl();

                }, 
                error: function(r){
                    console.log("error");
                    console.log(r);
                }
            });
            return this;
        }
        return this;
    },

これは、初期化の直後に配置されたインデックス関数であり、上記の初期化で作成されたビューをレンダリングしますが、Cannot call method 'render' of nullエラーが発生します

index: function() {

        this._index.render();
    },
4

2 に答える 2

3

Backbone.history.start現在のURLに一致するルートをトリガーするため、ルーターの準備ができるまでルートの呼び出しを遅らせる必要があります。

したがってloadUrl$.ajax成功コールバックを呼び出す代わりに、依存関係がロードされるまで待機し、代わりにhistory.startを呼び出します。

success: function(data) {
    //...
    Backbone.history.start();
}
于 2013-01-21T08:42:32.263 に答える
1

XHRリクエストはデフォルトで非同期です。つまり、$.ajax呼び出しはブロックされず、最初のルートはすぐに一致し_indexますが、その時点ではまだ定義されておらず、エラーが発生します。

コードが次のようになっている場合は、

var r = new Gallery();
Backbone.history.start();

何が起こるか

  1. router.initializeと呼ばれる
  2. XHRリクエストが発行されます
  3. router.initialize終了します
  4. Backbone.history.startインデックスルートをトリガーします
  5. router.indexと呼ばれる
  6. XHRリクエストは

このフィドルをチェックして、問題を再現してくださいhttp://jsfiddle.net/nikoshr/krFtA/

あなたができるいくつかのこと:

  • 可能であれば、ページのロードでモデルをブートストラップします。これにより、リクエストといくつかの頭痛の種を節約できます。

  • データが利用可能になるまでブロックする同期リクエストを強制しasync: falseます(基本的に、あなたが考えていたものだと思います):

    $.ajax({
        async: false,
        url: 'galleries',
        dataType: 'json',
        data: {},
        success: function(data) {
            ...
        }, 
        error: function(r){
            ...
        }
    })
    

    http://jsfiddle.net/nikoshr/m3dW5/

  • @fencliffが言ったように、Backbone.history.start準備ができるまで遅らせてください。

  • またはjQuery>=1.5の場合、遅延オブジェクトを使用してリクエストとレンダリングを同期できます

    var PhotoCollection = Backbone.Collection.extend({
        url: 'galleries',
    
        initialize: function() {
            this.loaded = $.Deferred();
        },
    
        fetch: function(opts) {
            var ld = this.loaded,
                xhr = Backbone.Collection.prototype.fetch.call(this, opts);
            xhr.always(ld.resolve);
        }
    });
    
    var IndexView = Backbone.View.extend({
        el: '#v',
        initialize: function() {
            _.bindAll(this);
        },
        render: function() {
            this.$el.html('rendered');
            console.log('render');
        }
    });
    
    var Gallery = Backbone.Router.extend({
        routes: {
            "": "index"
        },
    
        _index: null,
    
        initialize: function(options) {
            this._photos = new PhotoCollection();
            this._photos.fetch();
            this._index = new IndexView({model: this._photos});
            console.log(this._index);
        },
    
        index: function() {
            var view = this._index;
            view.model.loaded.always(view.render);
        }
    });
    

    http://jsfiddle.net/nikoshr/m3dW5/1/

于 2013-01-21T10:03:11.390 に答える