Angular Datatables Sometimes Fails To Load

1.3k views Asked by At

I have a angular datatable which sometimes just fails to load with the following error:

angular.js:13708 TypeError: Cannot read property 'mData' of undefined
at HTMLTableCellElement.<anonymous> (jquery.dataTables.js:1197)
at Function.each (jquery-3.1.0.min.js:2)
at r.fn.init.each (jquery-3.1.0.min.js:2)
at HTMLTableElement.<anonymous> (jquery.dataTables.js:1194)
at Function.each (jquery-3.1.0.min.js:2)
at r.fn.init.each (jquery-3.1.0.min.js:2)
at r.fn.init.DataTable [as dataTable] (jquery.dataTables.js:869)
at r.fn.init.$.fn.DataTable (jquery.dataTables.js:15134)
at Object.renderDataTable (angular-datatables.js:757)
at Object.hideLoadingAndRenderDataTable (angular-datatables.js:773)

I already read, that this can happen if there is no head or no body or in case of a missmatch in number of columns in header and body. But I can rule out this two issues, as my table is loaded correctly sometimes.

The data behind the table is fetched once from my database and is not changing in the controller, so we can assume, that this also can't cause an error with the col/row missmatch.

Here my controller:

angular.module('my-controllers').controller('tvShowGraficsController', ['$scope', '$q', 'SeasonService', 'TvShowService', 'UtilityService', 'DTOptionsBuilder',
    function ($scope, $q, SeasonService, TvShowService, UtilityService, DTOptionsBuilder) {

        var util = UtilityService;

        var filter_by_weight = function (link) {
            return (link.weight >= $scope.slider.min) && (link.weight <= $scope.slider.max);
        };

        var set_force_directed_data = function (data) {
            var force_data_all = data.force_directed_data,
                nodes = force_data_all.nodes,
                links = force_data_all.links;

            links = links.filter(filter_by_weight);

            $scope.slider.options.ceil = $scope.max_weight;

            $scope.forceDirectedData = {
                links: links,
                nodes: nodes
            };
        };

        TvShowService.GetTvShow().then(function (result) {
            $scope.tv_show = result.data;

            $scope.max_weight = Math.max.apply(Math, result.data.force_directed_data.links.map(function (o) {
                return o.weight;
            }));

            set_force_directed_data(result.data);

            var replica_lengths = $scope.tv_show.replicas_length_list;
            var length_list = [];

            for (var len in replica_lengths) {
                if (replica_lengths.hasOwnProperty(len)) {
                    length_list.push([+len.substring(1), replica_lengths[len], "Test"])
                }
            }

            length_list.sort(util.sort_by_key(0));

            $scope.tvShowReplicaLengths = [{
                key: "Quantity",
                bar: true,
                values: length_list.slice(1, 51)
            }];

            var reversed_length_list = jQuery.extend(true, [], length_list);
            reversed_length_list.sort(util.sort_by_key(1));

            $scope.tvShowReplicaLengthsDistribution = reversed_length_list;
        });

    ........

    $scope.dtOptions = DTOptionsBuilder.newOptions()
        .withDOM('frtip')
        .withButtons([
            {
                extend: 'csv',
                text: 'Download as CSV'
            },
            {
                extend: 'excel',
                text: 'Download as XLS'
            }
    ]);
}]

);

And my HTML:

<div class="col-md-12">
            <div class="panel panel-primary" ng-if="tv_show">
                <div class="panel-heading">
                    <h3 class="panel-title">Configuration Matrix</h3>
                    <span class="pull-right clickable"><i
                            class="glyphicon glyphicon-chevron-up"></i></span>
                </div>
                <div class="panel-body">
                    <table datatable="ng" dt-options="dtOptions" id="config-matrix" class="row-border hover">
                        <thead>

                        <th>Speaker/Season</th>
                        <th ng-repeat="n in [] | range:all_seasons.length+1">{{n}}</th>

                        </thead>
                        <tbody>
                        <tr ng-repeat="season in tv_show.configuration_matrix">
                            <td ng-repeat="values in season track by $index"
                                ng-class="setColor(values)">
                                {{values}}
                            </td>
                        </tr>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>

Imports:

 <script src="https://code.jquery.com/jquery-3.1.0.min.js"
        integrity="sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s=" crossorigin="anonymous"></script>
<script type="text/javascript" charset="utf8" src="//cdn.datatables.net/1.10.13/js/jquery.dataTables.js"></script>
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/angular-datatables/dist/angular-datatables.js"></script>

<script src="//cdn.datatables.net/buttons/1.2.2/js/dataTables.buttons.min.js"></script>
<script src="//cdn.datatables.net/buttons/1.2.2/js/buttons.colVis.min.js"></script>
<script src="//cdn.datatables.net/buttons/1.2.2/js/buttons.flash.min.js"></script>
<script src="//cdn.datatables.net/buttons/1.2.2/js/buttons.html5.min.js"></script>
<script src="//cdn.datatables.net/buttons/1.2.2/js/buttons.print.min.js"></script>

<script src="bower_components/angular-datatables/dist/plugins/buttons/angular-datatables.buttons.js"></script>
<script src="bower_components/angular-datatables/dist/plugins/bootstrap/angular-datatables.bootstrap.js"></script>
<script src="bower_components/angular-datatables/dist/plugins/tabletools/angular-datatables.tabletools.js"></script>

Anyone an idea, what might went wrong here?

1

There are 1 answers

0
Igl3 On BEST ANSWER

I found the issue. For the header I get the column values in another function then I use for getting the body values.

As both functions work asynchronously it sometimes happens, that the values for the body are loaded by angular before the values for the header are ready.

So for everyone facing a similar issue: If you get the data for the head of the table somewhere else than you get your data for the body, check if both are ready before loading the datatable.