jQuery,Dialog,Tabs和DataTables:如何在继续之前等待一个人完成?

时间:2014-01-09 03:40:36

标签: javascript jquery jquery-ui datatables jquery-datatables

我有一个棘手的问题,可以通过链式回调解决,但这导致相当复杂的代码。

我有一些嵌套组件:jQueryUI对话框。在其中,我有jQueryUI选项卡。在每个选项卡中,我有一个DataTables组件,调用AJAX数据。

我的问题是,当我在对话框中加载所有HTML时,所有内容都会并行启动:标签尝试创建自己,而每个DataTable同时收集它的数据!

结果是完全混乱:Tabs不包含正确的元素,因为每个DataTable在Tabs初始化之后在DOM上创建新节点。 Dialog采用了错误的维度,因为DOM在初始化时很小,但在每个DataTable显示数据时都会长大。

为了使事情有效,我需要:

1) Wait for each DataTable to initialize.
2) When they're all done, initialize the Tabs.
3) When Tabs are ready, finally open the Dialog.

有一种简单的方法吗?我目前正在使用大量的回调,并且所有内容都是动态的,数据库驱动的,所以我必须进行大量的泛化,几乎没有什么可以硬编码。事情已经奏效,但它很难看!

如果可以的话,这是我会关闭JavaScript异步行为并使其全部同步和顺序的情况之一。

也许jQuery队列,承诺或类似的东西可以帮助我?任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:1)

我找到了合适的解决方案,因此我会在此发布,以帮助其他遇到类似问题的人。

首先,我发现DataTables在创建时触发了一个事件。这是“init”事件:

$("#TableID").on("init", function() { whatever(); } );

其次,我的另一个问题是在初始化选项卡之前我必须等待的不确定数量的DataTable。所以我创建了一个名为RenderManager的小函数来跟踪我的所有DataTable。当最后一个完成时,将调用回调。我使这个功能非常通用,所以它可以用在任何需要等待几个并行处理才能完成的情况下:

function RenderManager(action, id, callback) 
{
  if(typeof RenderManager.groups == 'undefined' ) RenderManager.groups = {};

  switch(action)
  {
    case "init":
      RenderManager.groups[id] = { _callback:callback, _counter:0 };
    break;
    case "add":
      if(typeof RenderManager.groups[id] == 'undefined' ) 
        console.log('Group "'+id+'" referenced before init.');
      else 
        RenderManager.groups[id]._counter++;
    break;
    case "remove":
      if(typeof RenderManager.groups[id] == 'undefined' ) 
        console.log('Group "'+id+'" referenced before init.');
      else
      {
        RenderManager.groups[id]._counter--;
        if(RenderManager.groups[id]._counter == 0) 
          RenderManager.groups[id]._callback();
      }
    break;
  }
}

用法很简单:首先,使用init调用它,以通知组名称和所需的回调:

RenderManager('init', 'MyGroup', function() { CreateTabs(); });

对于创建的每个DataTable(或并行proccess),将其添加到组中:

RenderManager('add', 'MyGroup');

然后将remove绑定到每个DataTable的init事件(或任何并行进程的完成),使用:

$("#TableID").on("init", function() { RenderManager('remove', 'MyGroup'); } );

就是这样!当最后一个DataTable完成它的工作时,无论执行顺序如何,都将调用CreateTabs();,无论哪个DataTable首先完成。

正如您所看到的,此函数只是一个计数器:当“堆栈”返回到零时,回调将触发。它可以通过注册每个元素的ID来改进,但这对我目前正在解决的问题来说是过度的。