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 路由器的初始化检查索引是否为空,如果是,则使用数据创建一个新视图。

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 回答