延迟索引的渲染,直到初始化完成

时间:2013-01-20 22:08:46

标签: backbone.js

我想知道为什么渲染索引函数的尝试给我一个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,如果是,则创建带有数据的新视图。

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();
    },

2 个答案:

答案 0 :(得分:3)

Backbone.history.start会触发与当前网址匹配的路由,因此您需要延迟调用它,直到您的路由器准备就绪。

因此,不要在loadUrl成功回调中调用$.ajax,而是等待加载依赖项并调用history.start:

success: function(data) {
    //...
    Backbone.history.start();
}

答案 1 :(得分: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请求结束
  7. 检查此小提琴以重现您的问题http://jsfiddle.net/nikoshr/krFtA/

    你可以做的一些事情:

    • 如果可能,bootstrap models in your page load,这将为您节省请求和一些麻烦,

    • 强制使用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,您可以使用deferred object来同步您的请求和渲染

      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/