Meteor with DataTables: Meteor._atFlush TypeError

依然范特西╮ 提交于 2019-12-17 20:27:15

问题


I'm trying to use DataTables (via mrt add datatables) with Meteor. I've variously tried adding the $('#mytableid').dataTable() to the Meteor.subscribe callback, Meteor.autorun, Meteor.startup, and Template.mytemplate.rendered -- all resulting in the following exception and a No data available in table message.

Any pointers?

    Exception from Meteor._atFlush: TypeError: Cannot call method 'insertBefore' of null
        at http://localhost:3000/packages/liverange/liverange.js?bc1d62454d1fefbec95201344b27a7a5a7356293:405:27
        at LiveRange.operate (http://localhost:3000/packages/liverange/liverange.js?bc1d62454d1fefbec95201344b27a7a5a7356293:459:11)
        at LiveRange.replaceContents (http://localhost:3000/packages/liverange/liverange.js?bc1d62454d1fefbec95201344b27a7a5a7356293:403:17)
        at http://localhost:3000/packages/spark/spark.js?c202b31550c71828e583606c7a5e233ae9ca50e9:996:37
        at withEventGuard (http://localhost:3000/packages/spark/spark.js?c202b31550c71828e583606c7a5e233ae9ca50e9:105:16)
        at http://localhost:3000/packages/spark/spark.js?c202b31550c71828e583606c7a5e233ae9ca50e9:981:9
        at http://localhost:3000/packages/deps/deps-utils.js?f3fceedcb1921afe2b17e4dbd9d4c007f409eebb:106:13
        at http://localhost:3000/packages/deps/deps.js?1df0a05d3ec8fd21f591cfc485e7b03d2e2b6a01:71:15
        at Array.forEach (native)
        at Function._.each._.forEach (http://localhost:3000/packages/underscore/underscore.js?47479149fe12fc56685a9de90c5a9903390cb451:79:11)

Update: Potentially related to this issue, for which the best solution found was to call dataTable() for each row -- not ideal in that case, and potentially catastrophic in mine given the very large number of rows.


回答1:


Dror's answer is the right start for sure. Here's the best practice the way I see it currently:

HTML

<template name="data_table">
    {{#constant}}
        <table class="table table-striped" id="tblData">
        </table>
    {{/constant}}
</template>

JS:

Template.data_table.created = function() {
    var _watch = Collection.find({});
    var handle = _watch.observe({
        addedAt: function (doc, atIndex, beforeId) {
            $('#tblData').is(":visible") && $('#tblData').dataTable().fnAddData(doc);
        }
        , changedAt: function(newDoc, oldDoc, atIndex) {
            $('#tblData').is(":visible") && $('#tblData').dataTable().fnUpdate(newDoc, atIndex);
        }
        , removedAt: function(oldDoc, atIndex) {
            $('#tblData').is(":visible") && $('#tblData').dataTable().fnRemove(atIndex);
        }
    });
};

Template.data_table.rendered = function () {

    if (!($("#tblData").hasClass("dataTable"))) {
        $('#tblStudents').dataTable({
            "aaSorting": []
            , "sDom": "<'row-fluid'<'span6'l><'span6'f>r>t<'row-fluid'<'span6'i><'span6'p>>"
            , "sPaginationType": "bootstrap"
            , "oLanguage": {
                "sLengthMenu": "_MENU_ records per page"
            }
            , "aoColumns": [
                { "sTitle": "First Data", "mData": function (data) { return data.firstData },
            ]
        });

        $('#tblData').dataTable().fnClearTable();
        $('#tblData').dataTable().fnAddData(Collection.find().fetch());
    }
};



回答2:


Since Meteor is reactive, you need to create an empty table first and then add the rows.

Create the table:

$('#myTable').dataTable( {
    "aoColumns": cols, //the column titles
    "sDom": gridDom
} );

Add rows should look something like:

 var myCursor = myCollection.find({});
 var handle = myCursor.observe({
  added: function (row) {
   //Add in here the data to the table
  },

});




回答3:


The answered approach still stands but requires some changes after two years.

  1. There is no such thing as constant anymore.
  2. Instead of an empty table, put the thead but NOT the tbody. This way, columns are defined properly.
  3. Put the observer in the onRendered (not rendered anymore) and NOT on onCreated (not created anymore). Otherwise, table is only filled at first creation and not when you come back.
  4. clear and fill methods on the onRendered are not required.
  5. In the observe method, make sure that you are adding an array and not an object. Otherwise fnAdd cannot render content
  6. fnRemove is no more. Use fnDeleteRow instead
  7. I'm not sure if the "is visible check" is required or not. There does not seem to be a problem when you remove it too, so I removed it.

With the above remarks, here is the code:

Template.creamDealsList.onRendered(function () {
   if (!($("#tblData").hasClass("dataTable"))) {
      $('#tblStudents').dataTable({
        // Those configuration are not really important, use it as they are convenient to you
        "aaSorting": []
        , "sDom": "<'row-fluid'<'span6'l><'span6'f>r>t<'row-fluid'<'span6'i><'span6'p>>"
        , "sPaginationType": "bootstrap"
        , "oLanguage": {
            "sLengthMenu": "_MENU_ records per page"
        }
        , "aoColumns": [
            { "sTitle": "First Data", "mData": function (data) { return data.firstData },
        ]
    });
   }
  var _watch = Collection.find({});
  var convertDocToArray = function (doc) {return [doc._id, doc.name]}
  var handle = _watch.observe({
    addedAt: function (doc, atIndex, beforeId) {
        $('#tblData').dataTable().fnAddData(convertDocToArray(doc));
    }
    , changedAt: function(newDoc, oldDoc, atIndex) {
        $('#tblData').dataTable().fnUpdate(convertDocToArray(newDoc), atIndex);
    }
    , removedAt: function(oldDoc, atIndex) {
        $('#tblData').dataTable().fnDeleteRow(atIndex);
    }
  });
})

And simple HTML would be like:

<template name="data_table">
    <table class="table table-striped" id="tblData">
        <thead>
            <th>Id</th>
            <th>Name</th>
        </thead>
    </table>
</template>

This worked at least for me. I'm not seeing flush errors anymore. And also, when you render later, sometimes, there was a no data available message in the datatable and that disappeared as well.




回答4:


Here's my implementation of dataTables in Meteor, using CoffeeScript and HTML. It works, and it's simpler, but may be less efficient than the existing answers for large tables (it's quick in my case though).

Template Function

Template.dashboard.rendered = ->

  # Tear down and rebuild datatable
  $('table:first').dataTable
    "sPaginationType": "full_numbers"
    "bDestroy": true

HTML

<template name="dashboard">
  <table class="table table-bordered" id="datatable_3" style="min-width:1020px">
    <thead>
      <!-- code removed to save space -->
    </thead>
    <tbody id="previous-jobs-list">
      {{#each jobs}}
        {{> jobRow}}
      {{/each}}
    </tbody>
  </table>
</template>

<template name="jobRow">
  <tr>
    <td><a href="/jobs/{{number}}">{{number}}</a></td>
    <td>{{normalTime date}}</td>
    <!-- more code removed to save space -->
  </tr>
</template>

Where dashboard.jobs is a simple .find(...) on the collection.



来源:https://stackoverflow.com/questions/14925420/meteor-with-datatables-meteor-atflush-typeerror

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!