【问题标题】:How to prevent Backbone.Marionette from rendering a view if it's model hasn't been fetched?如果尚未获取模型,如何防止 Backbone.Marionette 渲染视图?
【发布时间】:2012-11-14 01:47:43
【问题描述】:

在我的backbone.Marionette 应用程序中,我有一个模型,它需要一个Id 属性来构造它的url。因此,我通过将 Id 传递给模型来创建模型,将其添加到视图中,然后获取模型:

   model = new Model({_id:id})               
   view = new View({model:model})                               
   app.content.show(view)                                                    
   model.fetch()

我希望视图仅在获取模型后才开始渲染,但 Marionette 会立即渲染模型,导致我的模板渲染失败,因为预期的属性不存在。有什么解决方法吗?

我正在尝试做类似于此处接受的答案的事情: Binding a Backbone Model to a Marionette ItemView - blocking .fetch()?

但正如答案中所述,虽然这适用于主干,但 Marionette 会自动呈现视图。

另见: Backbone Marionette Displaying before fetch complete

【问题讨论】:

标签: backbone.js marionette


【解决方案1】:

以上两个答案都有效。
这是我更喜欢使用的另一种方式(感觉更 backboney)。

将视图直接绑定到模型
获取模型完成后,您指定的函数将运行。 这可以通过模型集合来完成。

var Model = Backbone.Model.extend({});
var model = new Model();
model.fetch();

var View = Marionette.ItemView.extend({
    model:model,
    initialize: function(){
        this.model.bind("sync", this.render, this);// this.render can be replaced
    }                                              // with your own function
});                               

app.region.show(new View);                                           

这也使您可以随时获取。

【讨论】:

【解决方案2】:

如果你真的想在模型被获取之前阻止渲染,你应该像这样重新排序你的调用:

model = new Model({_id:id});
view = new View({model:model});
model.fetch({success: function () {
  app.content.show(view);
});

或者,您应该考虑立即渲染并利用 Marionette 的空白状态支持。

【讨论】:

  • 我最终使用了类似的东西,但我希望木偶内置了一些东西来处理这种情况。谢谢。
  • 您能详细解释一下 Marionette 的空白状态支持吗?
【解决方案3】:

基于 Derick Bailey 的一个例子:

 model = new Model({_id:id})               
   var fetched = model.fetch();

  // wait for the model to be fetched
  $.when(fetched).then(function(){

     view = new View({model:model})                               
     app.content.show(view)     
  });

【讨论】:

  • 谢谢,这与在 fetch 的成功处理程序中处理它基本相同,尽管我更喜欢这种方式。
  • 嗨,不完全是,有时 fetch 可以在渲染 dom 之前返回,延迟对象可以在这里提供帮助
  • 延迟真正有趣的地方是当您需要在多个数据源被感染后渲染视图时(请参阅davidsulc.com/blog/2013/04/02/…)。因此,即使只获取一个源,使用延迟也可以让您的代码保持一致。
  • 感谢 David,这确实是一个比 deferred 更好的用例。
【解决方案4】:

我最近遇到了同样的问题,并决定使用 Marionette 的事件系统让视图在触发 show() 之前传达它们的状态。我也在使用 requireJS,它增加了一些额外的复杂性 - 但这种模式有帮助!

我将有一个带有 UI 元素的视图,当单击该元素时,会触发一个事件以加载新视图。这可能是子视图或导航视图 - 没关系。

App.execute('loadmodule:start', { module: 'home', transition: 'left', someOption: 'foo' });

该事件被 Wreqr 'setHandlers' 捕获并触发视图加载序列(在我的情况下,我正在执行一堆逻辑来处理状态转换)。 “开始”序列初始化新视图并传入必要的选项。

var self = this;
App.commands.setHandlers({'loadmodule:start': function( options ) { self.start( options );

然后正在加载的视图处理集合/模型并在初始化时获取。视图监听模型/集合的变化,然后使用 wreqr 的 executre 命令触发一个新的“就绪”事件。

this.listenTo( this.model, 'change', function(){
    App.execute('loadmodule:ready', { view: this, options: this.options });
}); 

我有一个不同的处理程序来捕获该就绪事件(和选项,包括视图对象引用)并触发 show()。

ready: function( options ) {

// catch a 'loadmodule:ready' event before proceeding with the render / transition - add loader here as well

var self = this;
var module = options.options.module;
var view = options.view;
var transition = options.options.transition;
var type = options.options.type;

if (type === 'replace') {
    self.pushView(view, module, transition, true);
} else if (type === 'add') {
    self.pushView(view, module, transition);
} else if (type === 'reveal') {
    self.pushView(view, module, transition, true);
}   

},


pushView: function(view, module, transition, clearStack) {

var currentView = _.last(this.subViews);
var nextView = App.main.currentView[module];
var self = this;

var windowheight = $(window).height()+'px';
var windowwidth = $(window).width()+'px';
var speed = 400;

switch(transition) {
case 'left':

    nextView.show( view );

    nextView.$el.css({width:windowwidth,left:windowwidth});
    currentView.$el.css({position:'absolute',width:windowwidth,left:'0px'});

    nextView.$el.animate({translate: '-'+windowwidth+',0px'}, speed, RF.Easing.quickO);
    currentView.$el.animate({translate: '-'+windowwidth+',0px'}, speed, RF.Easing.quickO, function(){

        if (clearStack) {
            _.each(_.initial(self.subViews), function( view ){
                 view.close();
            });
            self.subViews.length = 0;
            self.subViews.push(nextView);
        }

    });

break;

我将尝试写出整个系统的体面要点,并在下周左右发布到这里。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-25
    • 2011-09-05
    • 1970-01-01
    • 1970-01-01
    • 2013-11-16
    • 1970-01-01
    相关资源
    最近更新 更多