将Backbone Model绑定到Marionette ItemView - 阻止.fetch()?

时间:2012-05-17 21:02:26

标签: javascript backbone.js marionette

这是一个2部分问题。 1)是否有更好的方法将模型异步渲染到视图中?我目前正在使用模型中的fetch方法创建ajax请求(虽然我在启动时显式调用它),然后使用应用程序事件呈现模板化视图{{ 1}},在调用vent方法后从模型内部发布。很酷但很不稳定? 2)阻塞parse方法是否可以使用,是否可能?

应用程序将其呈现到页面:

fetch

然后它获取模型并呈现:

layout
navbar
index

但是,如果我不使用layout navbar thing 1 something somethingelse 触发器,它(预期)会呈现:

vent

html模板:

layout
navbar
thing
1
null
null

app.js

<!-- Region: NavBar -->
<script type="text/template" id="template-navbar">
   <div id="navbar">
      navbar
   </div>
</script>

<!-- View: IndexView -->
<script type="text/template" id="template-index">
   <div id="index">
      index
   </div>
</script>

<!-- View: ThingView -->
<script type="text/template" id="template-thing">
   <div id="thing">
      thing<br/>
      <%= id %><br/>
      <%= valOne %><br/>
      <%= valTwo %><br/>
   </div>
</script>

<!-- Region -->
<div id="default-region">
  <!-- Layout -->
  <script type="text/template" id="template-default">
     layout
     <div id="region-navbar">
     </div>
     <div id="region-content">
     </div>
  </script>
</div>

2 个答案:

答案 0 :(得分:35)

从一个非常基本的角度来看,抛开你提供的具体例子,这就是我如何解决问题和解决方案。

通用问题/解决方案

以下是问题的通用版本:

  • 您需要通过其ID获取模型。
  • 获取模型后需要渲染视图。

这很简单。在获取数据之前将模型附加到视图,然后使用模型的“sync”事件来呈现视图:

MyView = Backbone.View.extend({
  initialize: function(){
    this.model.on("sync", this.render, this);
  },

  render: function(){ ... }
});


myModel = new MyModel({id: someId});
new MyView({
  model: myModel
});

myModel.fetch();

注意事项:

我在模型上调用fetch之前设置了带有id的模型和模型的视图。这是为了防止加载数据和渲染视图之间的竞争条件。

我在这里指定了通用Backbone的东西。 Marionette通常会一样,但会为你做渲染。

您的具体需求

阻止抓取

糟糕的想法,到处都是。不要试试。

阻止抓取将使您的应用程序完全无响应,直到数据从服务器返回。这将表现为一个应用程序,只要用户尝试执行任何操作,就会执行不良并冻结。

不执行此操作的关键是利用事件并确保在实际进行异步调用之前配置事件,如我的通用示例所示。

不要在模型的初始化程序中调用fetch。这是在寻找麻烦,因为在获取之前你将无法设置任何视图或事件。我很确定这将解决您在异步调用中遇到的大多数问题。

视图和模型之间的事件

首先,我会避免使用MyApp.vent在模型和视图实例之间进行通信。视图已经引用了模型,因此它们应该直接相互通信。

换句话说,模型应该直接触发事件,视图应该监听模型上的事件。这与我的简单示例的工作方式相同,但您可以让模型随时触发您想要的任何事件。

我还要确保使用Marionette视图的bindTo功能,以便在视图关闭时协助清理事件。

MyView = Backbone.Marionette.ItemView.extend({
  initialize: function(){
    this.bindTo(this.model, "do:something", this.render, this);
  }
});

MyModel = Backbone.Model.extend({
  doSomething: function(){
    this.trigger('do:something');
  }
});

myModel = new MyModel();
new MyView({
  model: myModel
});

myModel.doSomething();

其他项目

我认为还有其他一些项目会导致一些问题,或导致导致问题的奇怪情况。

例如,您在DOMReady事件中发生了太多事情:$ ->

这并不是说你从这个事件中执行的代码太多了,但是你在这个事件中定义的代码太多了。你不应该做更多的事情:

$ -> 
  App.MyApp.start(data)

也不要在此事件回调中定义您的Marionette.Application对象。这应该单独定义,以便您可以在DOMReady回调之外设置初始值设定项,然后通过app.start()调用触发它们。

查看BBCloneMail示例应用程序,获取有关渲染布局的示例,然后在加载数据和外部模板后填充其区域:

来源:https://github.com/derickbailey/bbclonemail

直播应用:http://bbclonemail.heroku.com/


我不认为我会以你想要的方式直接回答你的问题,但我提出的想法应该引导你得到你需要的答案。我希望它至少有帮助。 :)

答案 1 :(得分:7)

请参阅Derick关于解决此常见问题的新建议:https://github.com/marionettejs/backbone.marionette/blob/master/upgradeGuide.md#marionetteasync-is-no-longer-supported

简而言之,将异步代码从视图中移开,这意味着您需要为它们提供已经获取数据的模型。从Marionette升级指南中的示例:

 Marionette.Controller.extend({
  showById: function(id){
    var model = new MyModel({
      id: id
    });

    var promise = model.fetch();

    $.when(promise).then(_.bind(this.showIt, this));
  },

  showIt: function(model){
    var view = new MyView({
      model: model
    });

    MyApp.myRegion.show(view);
  }
});