backbone.js视图在模型提取之前呈现

时间:2012-02-09 22:46:10

标签: backbone.js

我正在尝试创建一个小的backbone.js应用程序,但是在处理事情的顺序。

在我的html文件中,标题中有两个脚本块:

<script type="text/template" id="model-template">
  <a href="#"><%= title %></a>
</script>

<script type="text/javascript">
  jQuery(function(){
    window.model.fetch();
  }); 
</script>

在我的app.js中,我定义了一个简单的模型,视图和路由器。

(function($) {

window.MyModel = Backbone.Model.extend({
    url: '/mymodel'
});

window.mymodel = new MyModel();

$(document).ready(function() {

    window.MyModelView = Backbone.View.extend({
        template: _.template($('#mymodel-template').html()), 

        initialize: function () {
            _.bindAll(this, 'render');
        },

        render: function () {
            var renderedContent = this.template(this.model.toJSON());
            $(this.el).html(renderedContent);
            return this;
        }
    });
});

window.MyApp = Backbone.Router.extend({
    routes: {
        '': 'home'
    },

    initialize: function () {
        this.myModelView = new MyModelView({
            model: window.mymodel
        });
    },

    home: function() {
        var $body = $('body');
        $body.empty();
        $body.append(this.myModelView.render().el);
    }
 });

 $(function() {
    window.App = new MyApp();
    Backbone.history.start({pushState: true});
 });

})(jQuery);

该应用程序由简单的sinatra应用程序提供服务。 url /mymodel提供静态json文件:

{
    "title": "My Model",
}

加载应用程序时,我在javascript控制台中收到错误:

Uncaught ReferenceError: title is not defined

问题似乎是,视图在从服务器获取模型之前呈现自身。为什么?

昨天,我关注了PeepCode的前两个backbone.js截屏视频。我试图将我的应用程序与截屏视频中的应用程序进行比较,但是看不出我的应用程序为什么需要工作的原因。

有什么建议吗?

5 个答案:

答案 0 :(得分:16)

在这种情况下,您应该引导模型数据,以便在页面加载时可用。

而不是

window.model.fetch();

将这样的内容放入(如果使用.erb)

<script>
    window.model = new MyModel(<%= @model.to_json %>);
</script>

否则,您需要在获取模型后呈现视图,例如

绑定视图以在模型更改时进行渲染

initialize: function () {
    _.bindAll(this, 'render');

    this.model.on("change", this.render);
},

或处理model.fetch的成功并呈现视图

window.model.fetch({
   success: function (model, response) { 
      window.MyApp.myModelView.render();
   }
});

答案 1 :(得分:5)

您还可以利用Backbone.Model.fetch()返回的延迟对象http://api.jquery.com/category/deferred-object/,如下所示:

window.MyModel = Backbone.Model.extend({
   url: '/mymodel'
});

//when the model is fetched, store a reference to the jQuery deferred object
window.MyModelFetch = window.MyModel.fetch();

window.MyModelView = Backbone.View.extend({
    template: _.template($('#mymodel-template').html()), 

    initialize: function () {
        _.bindAll(this, 'render');
    },

    render: function () {
        //reference the deferred object and use 'done' method 
        //to register a callback after complete
        window.MyModelFetch.done(function(){
             var renderedContent = this.template(this.model.toJSON());
             $(this.el).html(renderedContent);
             return this;
        }
    }
});

您可能想要创建骨干模型的扩展,该扩展模型在您的模型上存储您可以引用的延迟对象,如下所示:

 Backbone.DeferrableModel = Backbone.Model.extend({
      fetch: function(){
           this.fetching = Backbone.Model.prototype.fetch.apply(this, arguments);
           return this.fetching;
      }
 });

然后在你的视图渲染方法中,你可以这样说:

  render: function () {
        //the deferred reference is now directly referenced from your model
        this.model.fetching.done(function(){
             var renderedContent = this.template(this.model.toJSON());
             $(this.el).html(renderedContent);
             return this;
        }
    }    

使用扩展模型并在整个主干应用程序中遵循此模式非常方便。

答案 2 :(得分:1)

  

从服务器重置模型的状态。如果模型有用,则有用   从来没有填充数据,或者如果你想确保你   拥有最新的服务器状态。如果是,将触发“更改”事件   服务器的状态与当前属性不同。接受   传递的选项哈希中的成功和错误回调   (模型,回应)作为论据。

在这种情况下,您需要在成功回调中呈现视图。

model.fetch({
   error: function () {
   },
   success: function (model, response) { // model is ready now
      // do view stuff here
   }
});

答案 3 :(得分:1)

显然,从之前的答案中,你知道你需要渲染fetch成功回调,但是我认为你的问题不止于此。也就是说,您的主路由用于立即构建myModelView,而不是在其数据加载时。发生这种情况是因为您正在调用render()以附加到body。相反,尝试使用现有元素初始化视图。这样你就可以延迟渲染调用,直到fetch完成:

window.MyApp = Backbone.Router.extend({
    routes: {
        '': 'home'
    },

    initialize: function () {

    },

    home: function() {
        var $body = $(document.body).empty();
        var myModelEl = $("<div></div>").appendTo($body);

        this.myModelView = new MyModelView({
            model: window.mymodel,
            el: myModelEl
        });
    }
 });

现在,您尚未调用render(),但您的视图已按预期成功附加到DOM。

答案 4 :(得分:0)

您始终可以使用“默认”选项设置默认标题:http://documentcloud.github.com/backbone/#Model-defaults

相关问题