在父进程本身依赖于ajax调用的回调中使用ajax

时间:2018-11-08 10:47:34

标签: javascript jquery ajax

我正在使用一个使用DataTables生成HTML表的应用程序,该表由来自ajax请求的数据填充。

这很简单:

var substancesTable = $('#substancesTable').DataTable({
    "processing": true,
    "serverSide": true,
    "searching": false,
    "ajax": {
        "url": "/get-substances.json",
        "method": "POST",
        "cache": false,
        "dataSrc": function (json) {

            // Update non-Datatables UI elements and perform other functions based on the ajax response
            $('#numSubstances').html(json.recordsTotal);
            drawOptionsButton(json.isFiltering);

            // Must return data for DataTables to work
            return json.data;
        }
    },
    // ... 
});

DataTables提供了一个称为rowCallbackhttps://datatables.net/reference/option/rowCallback)的回调,该回调允许在绘制表后 对表行进行后处理。这里的关键是,它是对/get-substances.json的ajax请求的之后;该表必须填充有数据,因为此时该回调用于处理表中的数据。

rowCallback中,我在表中提供了行ID的数组-也就是说,该ID与<tr>中的#substancesTable元素相对应-然后继续扩展这些行行。我可以通过对行ID的数组进行硬编码来手动完成此操作,例如

 var substancesTable = $('#substancesTable').DataTable({
     // ...
     "rowCallback": function(row) {
       var id = $(row).find('td:first').text();
       var index = $.inArray(id, ['4', '7']); // hardcoded array

       if (index !== -1) {
           var tr = $(row).closest('tr');
           var row = substancesTable.row( tr );
           row.child.show();
           tr.addClass('active');
       }
 });

我已硬编码的数组表示在填充表后 将第4行和第7行展开,这等效于用户单击它们。

我遇到的问题是我不想对数组进行硬编码。该应用程序将等价var index存储在Redis(缓存)中,这意味着即使用户离开页面,我们也可以轻松地获取数据。因此,我添加了第二个ajax请求(在var substancesTable...块之外)以获取Redis数据。这会发出ajax请求以填充数组activeRows

var activeRows = [];
$.ajax({
    url: '/view-substance/get-active-rows',
    method: 'post',
    cache: false,
}).done(function(data) {
  activeRows = data;
  console.log(activeRows);
});

我了解ajax的本质意味着我的代码是异步的。在某些情况下,上面显示的ajax请求将在绘制DataTable之前完成,因此我得到console.log(activeRows)在呈现表之前出现,而在其他情况下,它随后发生。

发出第二个Ajax请求,以便可以使用其中的值代替硬编码数组的正确方法是什么?非常感谢,我需要将响应转换为数组(因为console.log语句中的响应仍然是JSON)。但是我的问题集中在将代码放在哪里,以便可以在rowCallback内可靠地使用它?

我已阅读How do I return the response from an asynchronous call?并了解异步性质。我不知道如何构造它以便在已经是ajax请求的一部分的回调中使用。

任何建议将不胜感激。

该应用程序使用DataTables版本1.10.16和jquery 3.2.1

2 个答案:

答案 0 :(得分:3)

您实际上可以使用ajax选项执行以下操作:

  1. 发出第一个AJAX请求,以检索活动行。

  2. 一旦检索到活动行,请进行第二个AJAX请求,以检索表数据。

示例:(请参阅完整的代码和演示here

var activeRows = [];

function getActiveRows() {
  return $.ajax({
    url: '/view-substance/get-active-rows',
    type: 'POST',
    dataType: 'json'
    ...
  }).done(function(data){
    activeRows = data;
    console.log(activeRows);
  });
}

function getTableData(data, callback) {
  return $.ajax({
    url: '/get-substances.json',
    type: 'POST',
    dataType: 'json',
    'data': data // must send the `data`, but can be extended using $.extend()
    ...
  }).done(callback); // and call callback() once we've retrieved the table data
}

$('#example').dataTable({
  ajax: function(data, callback){
    getActiveRows().always(function(){
      getTableData(data, callback);
    });
  },
  rowCallback: function(row, data){
    ...
  }
});

更新

在上面的示例中,我将AJAX调用分为两个不同的函数,主要是为了避免在调用ajax时在$('#example').dataTable()选项中出现长时间缩进。否则代码将如下所示:

var activeRows = [];

$('#example').dataTable({
  ajax: function(data, callback){
    // 1. Retrieve the active rows.
    $.ajax({
      url: '/view-substance/get-active-rows',
      type: 'POST',
      dataType: 'json'
      ...
    }).done(function(res){
      activeRows = res;
      console.log(activeRows);
    }).always(function(){
      // 2. Retrieve the table data.
      $.ajax({
        url: '/get-substances.json',
        type: 'POST',
        dataType: 'json',
        'data': data // must send the `data`, but can be extended using $.extend()
        ...
      }).done(callback); // and call callback() once we've retrieved the table data
    });
  },
  rowCallback: function(row, data){
    ...
  }
});

我使用了.always(),以便在检索活动行失败的情况下仍可以检索表数据。

答案 1 :(得分:1)

您可以通过Promises解决您的问题。承诺是帮助您管理和协调异步任务的对象。您的情况如下:

var activeRows = [];
var substancesTable = $('#substancesTable').DataTable({
     // ...
});

var pDataTable = new Promise(function(resolve, reject){
    // you wan't to resolve just once, 
    // after the table has finished processing the received data.
    // (You may want to change draw to an event that's more suitable)
    substancesTable.one('draw', resolve);
});

var pOpenRows = new Promise(function( resolve, reject ){

    $.ajax({
        url: '/view-substance/get-active-rows',
        method: 'post',
        cache: false,
    }).done(function(data) {
        // you can either save your rows globaly or give them to the resolve function
        // you don't have to do both
        activeRows = data; 
        resolve( data );
    });

});

// Here we basically create a third promise, which resolves (or rejects)
// automatically based on the promises in the array.
Promise.all([pDataTable, pOpenRows])
.then(function( values ){
    // expand your table rows here
    // Note: if you gave your rows to the resolve function you can access 
    // them here in values[1] (pDataTable's data would be in values[0])
});

如果您想进一步了解Promises:

有关浏览器支持的详细信息,您可以在这里查看: