Backbone.js 如何确保主干已完全呈现页面?

Backbone.js 如何确保主干已完全呈现页面?,backbone.js,views,rendering,backbone-views,viewrendering,Backbone.js,Views,Rendering,Backbone Views,Viewrendering,我使用BackboneJS处理大型企业应用程序。应用程序中的一个页面是通过REsT使用多个子系统调用构建的。如何确保加载页面所需的所有服务都已调用且模板绑定已完成 例如,我有一个主视图,它负责每个子视图的集合.fetch(),如下所示。 我为页面设置了一个视图,它负责呈现另外两个视图CustomerInfo和CustomerAccounts。景色是这样的 myApp.views.CustomerView = Backbone.View.extend({     initialize:

我使用BackboneJS处理大型企业应用程序。应用程序中的一个页面是通过REsT使用多个子系统调用构建的。如何确保加载页面所需的所有服务都已调用且模板绑定已完成

例如,我有一个
主视图
,它负责每个子视图的
集合.fetch()
,如下所示。

我为页面设置了一个视图,它负责呈现另外两个视图CustomerInfo和CustomerAccounts。景色是这样的

myApp.views.CustomerView = Backbone.View.extend({
        initialize: function() {
            var customerInfo = new myApp.collection.CustomerInfo();
            new myApp.views.CustomerInfo({el: $("#infoContainer"), collection: customerInfo});

            var customerAccount = new myApp.collection.CustomerAccount();
            new myApp.views.CustomerAccount({el: $("#accountContainer"), collection: customerAccount});
        }
});
CustomerInfo和CustomerAccount视图如下所示,


我想知道是否有任何方法可以从
myApp.views.CustomerView
中知道视图
CustomerInfo
CustomerAccounts
已完成渲染?这里我遇到的主要问题是
CustomerInfo
视图加载速度很快,但是
CustomerAccount
视图的加载需要一些时间。因此,当两个视图都在DOM上就绪时,我需要一次显示页面。

当您实例化视图时,为视图就绪事件添加一个侦听器。当视图完成数据提取和渲染时,使其自身触发数据 在父视图的渲染方法的末尾

self.trigger('view_ready');
在主视图中添加如下内容:

this.listenTo(CustomerInfoView, 'view_ready', this.customer_info_ready);
this.listenTo(CustomerAccountsView, 'view_ready', this.customer_account_ready);
然后在主视图或主模型中添加两个属性:info_ready和customer_ready,并将它们初始化为0 每次触发上述两个事件中的一个时,执行以下操作:

customer_info_ready : function(){
    this.model.set('info_ready',true);
    if (this.model.get('account_ready') === true) {
         this.trigger('both_elements_ready'); 
     }
}
customer_account_ready : function(){
    this.model.set('account_ready',true);
    if (this.model.get('info_ready') === true) {
         this.trigger('both_elements_ready'); 
     }
}
然后将侦听器添加到主视图上的“两个\u元素\u就绪”:

initialize: function() { 
 //your code
 this.on('both_elements_ready',this.page_ready); }

编辑:添加信息,使答案与问题更相关,更详细。

编辑:这个答案的灵感来源于我从“卓别林早午餐”示例中学到的东西。是建在主干上的框架


好的,我将推荐一个基于coffeescript的解决方案(我正好有一个coffeescript中的解决方案:/!如果您想转换回js,请尝试使用)

大师班 我们的想法是要有一个主类,而不是视图,它将把应用程序放在手上,而不是主视图

module.exports = class Application
  initialize: (finished_init) =>
    @collection = new Collection()
    @main_view = new View()
    @collection.fetch(
      success: (collection) =>
        @main_view.collection = @collection
        finished_init()
    )
  render: (targetLocation, params) ->
    switch targetLocation
      when "main" then (
        @main_view.render()
      )
initialize
方法中,我们获取采集数据。成功后,调用
finshed_init()
。您可以将其替换为
@render
(顺便说一句,
@
==this:)

初始化 以下是我如何初始化我的应用程序:

$ ->
  app = new Application()

  app.initialize( ->
    #----------------------------------#
    # Create the router and its routes
    # This is called at the finished_init() of the Application class
    #----------------------------------#
    app_router = new Router
  )
异步运行多个
fetche
您可以有一个监视fetche完成的函数,或您可以尝试使用的。它有一个很好的`并行函数,可以做到这一点

@collection1 = new Collection()
@collection = new Collection()
@main_view1 = new View()
@main_view2 = new View()

async.parallel [ (callback) ->
  setTimeout (->
    @collection1.fetch(
      success: (collection) =>
        @main_view1.collection = @collection
        callback null, "one"
  ), 200
, (callback) ->
  setTimeout (->
    @collection2.fetch(
      success: (collection) =>
        @main_view2.collection = @collection
        callback null, "two"
  ), 100
 ], (err, results) ->
   if not err
    @render()  # Render what you want

在打破我的脑袋很久之后,在谷歌上搜索,我发现

所以我对我的MasterView做了一些修改,它工作正常,解决了我遇到的问题。我在主视图中所做的更改如下

var activeConnections=0;

myApp.views.MasterView = Backbone.View.extend({
    initialize: function(params) {

        activeConnections++;

        var self = this;
        this.collection.fetch({
            success: function(resp) {

                activeConnections--;

                self.collection.bind("reset", self.render(), self);

                if(activeConnections===0){
                    // trigger the page has finished rendering
                }
            },
            error: function(xhr, xhrStatus) {
                // push error message, in case of fetch fails.
                if(activeConnections===0){
                    // trigger the page has finished rendering
                }
            }
        });
    },
    render: function() {
        var self = this;
        this.collection.each(function(model) {
            if (model.get('authorize') && model.get('status') === "success" && model.get('data').length > 0) {
                self.bindTemplate(model.get('data')[0]);
            }
        });
    }
});

感谢所有帮助我解决此问题的人。

感谢您的回复,但很抱歉,我无法在第一次发布时完成我的确切要求。根据你的建议,我会知道
CustomerInfoView
CustomerAccountsView
何时准备好,但我需要知道它们何时准备好。哇,这比问题还要复杂。如果你打算围绕一个框架工作,并使它比没有框架时更复杂,那么使用框架有什么意义呢?@RakanNimer:如果问题中提到的只有两个视图,那么你的解决方案可能会更好。但是,如果
myApp.views.CustomerView
@Pierreten您建议做什么?那么使用ChaplinJS可以以非常优雅的方式解决这个问题,那怎么办!只是一个观察:您的子视图真的不应该引用父视图(实际上,我认为没有视图应该引用另一个视图,但这完全是另一个主题),我还建议阅读一些关于如何更有效地使用主干的教程/示例;您的视图应该对模型/集合的更改作出反应;从目前的情况看,你的观点做得太多了。
@collection1 = new Collection()
@collection = new Collection()
@main_view1 = new View()
@main_view2 = new View()

async.parallel [ (callback) ->
  setTimeout (->
    @collection1.fetch(
      success: (collection) =>
        @main_view1.collection = @collection
        callback null, "one"
  ), 200
, (callback) ->
  setTimeout (->
    @collection2.fetch(
      success: (collection) =>
        @main_view2.collection = @collection
        callback null, "two"
  ), 100
 ], (err, results) ->
   if not err
    @render()  # Render what you want
var activeConnections=0;

myApp.views.MasterView = Backbone.View.extend({
    initialize: function(params) {

        activeConnections++;

        var self = this;
        this.collection.fetch({
            success: function(resp) {

                activeConnections--;

                self.collection.bind("reset", self.render(), self);

                if(activeConnections===0){
                    // trigger the page has finished rendering
                }
            },
            error: function(xhr, xhrStatus) {
                // push error message, in case of fetch fails.
                if(activeConnections===0){
                    // trigger the page has finished rendering
                }
            }
        });
    },
    render: function() {
        var self = this;
        this.collection.each(function(model) {
            if (model.get('authorize') && model.get('status') === "success" && model.get('data').length > 0) {
                self.bindTemplate(model.get('data')[0]);
            }
        });
    }
});