Skip to content
This repository was archived by the owner on Feb 2, 2025. It is now read-only.

Cannot Reinitialise DataTable #1160

Closed
bilalahmed54 opened this issue Jan 5, 2018 · 13 comments
Closed

Cannot Reinitialise DataTable #1160

bilalahmed54 opened this issue Jan 5, 2018 · 13 comments
Milestone

Comments

@bilalahmed54
Copy link

bilalahmed54 commented Jan 5, 2018

I have a WebSocket connection that updates my tables if there is a change in a row data, when the WebSocket get the message of the change, the code do the work and splice and push the data to the model bound with table, and I have to use $scope.$apply() to see the visual update, and after using $apply the table disappear from the view.

This is how I am initializing my data table:

    //Data table options
    vm.dtOptions = {
      dom: '<"top"f>rt<"bottom"<"left"<"length"l>><"right"<"info"i><"pagination"p>>>',
      //default number of records per page
      pageLength: 5,
      //It can be simple or full_numbers
      pagingType: 'full_numbers',
      autoWidth: false,
      responsive: true,
      //to hide search box
      bFilter: false,
      //select from drop down list to select number of records per page
      lengthMenu: [5, 10, 25, 50]
    };

And below id my HTML code:

<table class="dataTable row-border hover"   datatable="ng" dt-options="vm.dtOptions">

            <thead>
            <tr>
              <th translate="callParkGadget.parkedSince"></th>
            </tr>
            </thead>
            <tbody>
                <tr ng-repeat="parkedCall in parkedCallsList">
                     <td data-column="Caller">{{parkedCall.caller}}</td>
            </tr>
    </tbody>
</table>

I am using the following bower dependencies:

"jquery": "3.2.1",
"angular": "^1.6.2",
"angular-datatables": "0.6.0",

And this is the exact message I get in the pop-up:

DataTables warning: table id=DataTables_Table_0 - Cannot reinitialise DataTable. For more information about this error, please see http://datatables.net/tn/3

And after this error table is disappeared and I had to refresh the page to get it in its actual shape. Any help would be highly appreciated.

@bilalahmed54 bilalahmed54 changed the title Cannot reinitialise DataTable Cannot Reinitialise DataTable Jan 5, 2018
@ljmerza
Copy link

ljmerza commented Jan 5, 2018

I assume you are calling next() when the websocket updates the table? If so, you must destroy the table first before calling next(). Also try draw() on the dt instance instead to redraw after updating the data. I had to use setTimeout though to let angular update the DOM first then call draw()

@bilalahmed54
Copy link
Author

@ljmerza thanks for your reply. I'm not calling any next() or draw() method at any place. This is what I actually do when receive notification:

  $scope.$on('CALL_NOTIFICATION', function (event, args) {
      $timeout(function () {
            $scope.parkedCallsList.push(args.data.newCall);
       }, 500, true);
  });

And you can see in the HTML code given above in the question that I'm showing the same list (in which I'm pushing an element after receiving notification) with ng-repeat in HTML file. Please let me know If I'm missing anything which I need to add.

@ljmerza
Copy link

ljmerza commented Jan 5, 2018

You do need to call rerender when adding items to the array. Sure, Angular updated the DOM but Angular didn't notify datatables that the DOM updated

http://l-lin.github.io/angular-datatables/archives/#!/rerender

@bilalahmed54
Copy link
Author

Is this the reason that I'm getting Cannot Reinitialise DataTable error?
So, while adding an item to the array upon receiving notifications, I need to run Angular digest cycle to make changes available on the front end by $scope.$apply() and dtInstance.render() to re-render the table?
The table usually gets disappear when the last row in the table is removed that it gets disordered with the error message.

@l-lin
Copy link
Owner

l-lin commented Jan 7, 2018

This example should be close to what you want.
It seems the options of the DataTables are changed when you called $scope.apply(). You might want to watch its values.

@l-lin l-lin added the AngularJS label Jan 7, 2018
@bilalahmed54
Copy link
Author

bilalahmed54 commented Jan 7, 2018

@ljmerza @l-lin
I tried the following things and nothing seems working till now:

First Thing:
vm.dtInstance.reloadData();
For this, I just get the warning message on the browser's console and nothing happens:

The Angular Renderer does not support reloading data. You need to do it directly on your model

Second Thing:
vm.dtInstance.rerender();
After using this option, Datatable just keep showing Loading... hiding whole datatable.

Third Thing:
vm.dtInstance.DataTable.draw();
This doesn't give any error or warning but this doesn't seem to make any difference. To verify this option, I tried to apply search and re-draw table that if it still shows the filtered row or not but still all the data is being shown:
vm.dtInstance.DataTable.search("search_string").draw();

So, with all the options tried so far, I'm getting an error that when I add/remove data randomly based upon the async notification on web socket, sometimes table gets disordered and all the data gets disappears.

@bilalahmed54
Copy link
Author

@ljmerza @l-lin
Can you please respond on this? This is really annoying.

I dig into this further and found some more information related to issues being faced. Whenever I try to add/remove rows quickly (by adding data into the list bonded with table) or I add 2 rows then datatable gets disappear completely.

If there are a lot of issues then why unstable things are released or documentation isn't that much matured?

@rhorenov
Copy link

Hi guys @bilalahmed54 @l-lin,

I seem to have a very similar problem to this one (angular-datatables version 0.6.2)

@vinodf recomended a fix in his post here: #262 (comment) which helped to fix mine problem.

Could you give it a try?

If it helps we could perhaps try to persuade @l-lin to fix it in the code base.

Regards, Roman

rhorenov pushed a commit to rhorenov/angular-datatables that referenced this issue Jan 17, 2018
@l-lin
Copy link
Owner

l-lin commented Jan 27, 2018

Unfortunately, this fix solves some issues, but it also bring regression to other functionnalities, such as changing the data with the angular renderer.

rhorenov pushed a commit to rhorenov/angular-datatables that referenced this issue Feb 5, 2018
rhorenov pushed a commit to rhorenov/angular-datatables that referenced this issue Feb 5, 2018
@rhorenov
Copy link

rhorenov commented Feb 5, 2018

Hi Luis, yes you are right.

Please have a look at the second version of the fix:

rhorenov@03f5459

Probably not an ideal fix, but it works. In particular I was wondering what is the purpose of the _alreadyRendered variable and if it has anything to do with the problem.

Anyway, to the cause of the problem: it manifests when there is more than one successive change to the datatable's data (e.g. resizing the collection twice).

Normally a change to the datatable's data trigger the _parentScope.$watchCollection(...) callback function. The callback function destroys the table and schedules an another callback via $timeout() which in turn creates the underlying datatable. Seems fine.

What I mean by "_parentScope.$watchCollection(...) callback function" is this.
And I mean by "$timeout() callback function" is this.

The code directly:

_parentScope.$watchCollection(_ngRepeatAttr, function() {
    if (_oTable && _alreadyRendered) {
        _destroyAndCompile();
    }
    $timeout(function() {
        if (!_oTable) {
            _alreadyRendered = true;
            // Ensure that prerender is called when the collection is updated
            // See https://github.com/l-lin/angular-datatables/issues/502
            DTRendererService.preRender(renderer.options);
            var result = DTRendererService.hideLoadingAndRenderDataTable(_$elem, renderer.options);
            _oTable = result.DataTable;
            DTInstanceFactory.copyDTProperties(result, dtInstance);
            defer.resolve(dtInstance);
        }
    }, 0, false);
}, true);

Now, let's assume we have two successive changes to the size of the data.

The way the _parentScope.$watchCollection(...) callback function is written expects that the $timeout() callback function will be executed rather SOON after the execution of the _parentScope.$watchCollection(...) callback stops. Something like this:

_parentScope.$watchCollection(...) callback (change 1)
$timeout() callback (change 1)
_parentScope.$watchCollection(...) callback (change 2)
$timeout() callback (change 2)

Howewer, this order is NOT guaranteed and depends on many circumstances, so the execution order may look like this:

_parentScope.$watchCollection(...) callback (change 1)
_parentScope.$watchCollection(...) callback (change 2)
$timeout() callback (change 1)
$timeout() callback (change 2)

Which causes the underlying datatable to be initialized twice - and it complains.

Hope it makes sense. Regards, Roman

l-lin added a commit that referenced this issue Feb 8, 2018
@l-lin
Copy link
Owner

l-lin commented Feb 8, 2018

Thanks @rhorenov for your analyze. I commited your fix and I removed the flag _alreadyRendered (I forgot what it was used for) in the angular1 branch.
Please tell me if that works for you. I'll release a new version if it's all good for you.

@simonwfarrow
Copy link

Hi - I have the same issue as the OP - please could this fix be released?
I have tested the fix and can confirm it works.

@l-lin l-lin added this to the 0.6.3 milestone Aug 25, 2018
@l-lin
Copy link
Owner

l-lin commented Aug 25, 2018

My bad, totally forgot. I released the v0.6.3.

@l-lin l-lin closed this as completed Aug 25, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants