Search code examples
javascriptdatatables

How to Update live data with DataTables other pages


There is no problem updating the current page(websocket).
However, other pages are not updated, so filter is not working properly.


further explanation
There's about 2,000 data, updated in real time. If all 2000 data are displayed on one page without pagiation, all data is updated without any problems, and the ordering filter is also refreshed every 10 seconds with no problem. The problem is that when pagination is performed, for example, when displaying 100 data per page, Only 100 data is updated and the rest of the data is not updated. As a result, the ordering filter is not working properly.


-- js code
It is refreshed every 10 seconds(setInterval)
Customized for numerical sorting.(dom-text-numeric)

/* Create an array with the values of all the input boxes in a column, parsed as numbers */
$.fn.dataTable.ext.order['dom-text-numeric'] = function (settings, col) {
    return this.api()
        .column(col, {order: 'index'})
        .nodes()
        .map(function (td, i) {
            return $(td).text() * 1;
        });
};


/* Initialise the table with the required column ordering data types */
$(document).ready(function () {
    var myTable = $('#example').DataTable({
        responsive: true,
        //paging: false,
        pageLength:100,
        columns: [
            null,
            {orderDataType: 'dom-text-numeric'},
            {orderDataType: 'dom-text-numeric'},
            {orderDataType: 'dom-text-numeric'},
        ],
        order: [[1, 'desc']],

    });
    setInterval(function () {
        myTable.rows().invalidate().draw();
    }, 10000);


});

html--This is some rendered data.

 <table id="example" class="table table-striped table-bordered dt-responsive nowrap w-100 dataTable no-footer" style="width: 100%;" aria-describedby="example_info">
  <thead>
    <tr>
      <th class="sorting" tabindex="0" aria-controls="example" rowspan="1" colspan="1" aria-label="Name: activate to sort column ascending" style="width: 442px;">Name</th>
      <th class="sorting sorting_desc" tabindex="0" aria-controls="example" rowspan="1" colspan="1" aria-label="premium: activate to sort column ascending" style="width: 282px;" aria-sort="descending">premium</th>
      <th class="sorting" tabindex="0" aria-controls="example" rowspan="1" colspan="1" aria-label="binance: activate to sort column ascending" style="width: 292px;">binance</th>
      <th class="sorting" tabindex="0" aria-controls="example" rowspan="1" colspan="1" aria-label="upbit: activate to sort column ascending" style="width: 346px;">upbit</th>
    </tr>
  </thead>
  <tbody>
    <tr class="odd">
      <td class="name_DNT-BTC">DNT-BTC</td>
      <td class="premium_DNT-BTC sorting_1">1.0087</td>
      <td class="binanceSpot_DNTBTC" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00000233</td>
      <td class="upbitSpot_BTC-DNT" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00000231</td>
    </tr>
    <tr class="even">
      <td class="name_SNT-BTC">SNT-BTC</td>
      <td class="premium_SNT-BTC sorting_1">1.0072</td>
      <td class="binanceSpot_SNTBTC" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00000138</td>
      <td class="upbitSpot_BTC-SNT" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">-</td>
    </tr>
    <tr class="odd">
      <td class="name_TRX-BTC">TRX-BTC</td>
      <td class="premium_TRX-BTC sorting_1">1.0067</td>
      <td class="binanceSpot_TRXBTC" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00000299</td>
      <td class="upbitSpot_BTC-TRX" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">-</td>
    </tr>
    <tr class="even">
      <td class="name_ETH-USDT">ETH-USDT</td>
      <td class="premium_ETH-USDT sorting_1">1.0053</td>
      <td class="binanceSpot_ETHUSDT" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">1681.08</td>
      <td class="upbitSpot_USDT-ETH" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">1672.2989054</td>
    </tr>
    <tr class="odd">
      <td class="name_ETH-BTC">ETH-BTC</td>
      <td class="premium_ETH-BTC sorting_1">1.0050</td>
      <td class="binanceSpot_ETHBTC" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.073392</td>
      <td class="upbitSpot_BTC-ETH" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">-</td>
    </tr>
    <tr class="even">
      <td class="name_LINK-BTC">LINK-BTC</td>
      <td class="premium_LINK-BTC sorting_1">1.0047</td>
      <td class="binanceSpot_LINKBTC" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.0003658</td>
      <td class="upbitSpot_BTC-LINK" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00036409</td>
    </tr>
    <tr class="odd">
      <td class="name_LRC-BTC">LRC-BTC</td>
      <td class="premium_LRC-BTC sorting_1">1.0047</td>
      <td class="binanceSpot_LRCBTC" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00001917</td>
      <td class="upbitSpot_BTC-LRC" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">-</td>
    </tr>
    <tr class="even">
      <td class="name_BNT-BTC">BNT-BTC</td>
      <td class="premium_BNT-BTC sorting_1">1.0040</td>
      <td class="binanceSpot_BNTBTC" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00002527</td>
      <td class="upbitSpot_BTC-BNT" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00002537</td>
    </tr>
    <tr class="odd">
      <td class="name_EOS-BTC">EOS-BTC</td>
      <td class="premium_EOS-BTC sorting_1">1.0025</td>
      <td class="binanceSpot_EOSBTC" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.0000513</td>
      <td class="upbitSpot_BTC-EOS" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00005143</td>
    </tr>
    <tr class="even">
      <td class="name_XRP-BTC">XRP-BTC</td>
      <td class="premium_XRP-BTC sorting_1">1.0025</td>
      <td class="binanceSpot_XRPBTC" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00001574</td>
      <td class="upbitSpot_BTC-XRP" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00001578</td>
    </tr>
  </tbody>
</table>

--js -socket
Receives real-time data from the Beckend Consumer (via on-message.)

 function auto_reconnect_ticker_socket() {
    let ws = new WebSocket(
        'ws://' + window.location.host +
        '/ws/ticker?session_key=${sessionKey}')
    ws.onopen = function () {
        // subscribe to some channels
        ws.send(JSON.stringify({
            //.... some message the I must send when I connect ....
        }));
    };

    ws.onmessage = function (e) {
        let data = JSON.parse(e.data);
        let site = data['site'];
        let type = data['type'];

        if (type == 'ticker') {
            data['data'].forEach((c, i, a) => {
                document.querySelector(`.${site}_${c.symbol}`) && update_price(site, c.symbol, c.price_trade)
                document.querySelector(`.${site}_${c.symbol}`) && update_premium(c.name, c.premium)
                //&& update_price_change_24h(site, c.s, c.o, c.c)
            });
        }


    }

    ws.onclose = function (e) {
        console.log('Ticker Socket is closed. Reconnect will be attempted in 1 second.', e.reason);
        setTimeout(function () {
            auto_reconnect_ticker_socket();
        }, 1000);
    };

    ws.onerror = function (err) {
        auto_reconnect_ticker_socket.error('Socket encountered error: ', err.message, 'Closing socket');
        ws.close();
    };
    return ws
}

Is there a way to update other pages with the DataTables?


Solution

  • Your code is currently updating data in the DOM using query selectors such as:

    document.querySelector(`.${site}_${c.symbol}`) && update_price(site, c.symbol, c.price_trade)
    

    This will only update the HTML for data on the currently visible page (as you have noted). DataTables will not know anything about these changes.

    Instead you need to use the DataTables API when performing your data updates.

    One way to do this is to use a column containing a unique identifier - which in your case appears to be column 1 (index 0) - the "Name" column.

    To update existing records in the table, I would use the following approach.

    This assumes you get one name per socket event e. If you get an array of names, then you would adjust to loop through each one, and only perform one draw() at the end:

    function updateTable(e) {
      let pairData = JSON.parse(e.data);        
      // check if "name" already exists in table:
      var index = table.column( 0, {order:'index'} ).data()
        .indexOf( pairData.name);        
      if (index >= 0) {
        // update the existing row:
        table.row( index, {order:'index'} ).data( pairData ).draw();
      } else {
        // insert a new row:
        table.row.add( pairData ).draw();
      }
    }
    

    You will need to adjust the above for your specific JSON contents. I use data for the contents of a row, and name for the unique identifier in each row.

    indexOf() - searches in column zero and locates the row index containing the unique name (e.g. DNT-BTC). It uses {order:'index'} to ensure the value returned represents the internally assigned index number used by DataTables (based on the initial data load order), not an index number dependent on filtering and/or sorting.

    row().data( newdata ) - retrieves the row of data for the previously found index number. Updates the data for that row. Re-draws the table.

    Note that newdata can be an array or an object - depending on how the original row of data was created in DataTables. In my code, I assume an object (the JSON message). In your question, you show the original data as being provided directly from the initial HTML - so that would be an array of data, not an object:

    [ 'DNT-BTC', 1.0087, 0.00000233, 0.00000231 ]
    

    Finally, my code also inserts a new record, if its key value was not found anywhere in the DataTable. You may not need that, in your case.


    The benefit of this approach is that it operates on the underlying DataTable via its API, and not on the DOM, which may only display part of that underlying data. Also, if you only change values in the DOM, then any draw() call will cause that data to be lost (because such DOM changes do not exist in the underlying DataTables data).