2017-06-16 33 views
2

這一個很棘手,我會盡我所能地盡力解釋自己。Angular - Datatables:TypeError:無法讀取null的屬性'nodeName'

簡要說明:

我有數據表庫集成在我的角度項目,有它,因爲我幾個月前購買了該項目的主題。主題已更新,因此我用最新版本繼續更新了我的項目。

奇怪的是,什麼不工作是DataTables和DataTables沒有改變!

代碼故障:

從X組件我觸發我的共享服務IBOsService的方法。

當觸發此方法時,我的DatatableComponent導入Promise中的數據表庫。

直到現在,從來沒有這個問題。

DatatableComponent

this.tablesService.initTableData$.subscribe(() => { 
       if (!this.datatableInitialized) { 
        log.info('Starting script import promise'); 

        Promise.all([ 
         System.import('script-loader!my-plugins/datatables-bundle/datatables.min.js') 
        ]).then(values => { 
         log.data('success', JSON.stringify(values)); 
         this.render(); 
        }, reason => { 
         log.error('error', JSON.stringify(reason)); 
        }); 
       } 
      } 
     ); 

在我的控制檯我看到:DataTables success [{}]。因此,我明白這個承諾就是成功。

那麼我們再輸入this.render();的方法。

的方法一直持續到這條線的位置:

const _dataTable = element.DataTable(options); 

的事情是,在我的IDE,我可以瀏覽到所有變量,方法,等等......但我不能瀏覽到DataTable(),因此我猜測只是不認識這種方法,這就是爲什麼它會拋出錯誤。

,因爲腳本在加載的承諾,是正常的IDE不具備的數據表方法的映射......

全部組件代碼:

import { Component, Input, ElementRef, AfterContentInit, OnInit, Injectable, OnDestroy } from '@angular/core'; 
import { IBOsService } from '../../../+ibos/ibos.service'; 
import { Subscription } from 'rxjs/Subscription'; 
import { Log, Level } from 'ng2-logger'; 
import { logConfig } from '../../../../environments/log_config'; 

const log = Log.create('DataTables'); 
log.color = logConfig.dataTable; 

declare let $: any; 

@Component({ 

    selector: 'sa-datatable', 
    template: ` 
     <table class="dataTable {{tableClass}}" width="{{width}}"> 
      <ng-content></ng-content> 
     </table> 
    `, 
    styles: [ 
     require('my-plugins/datatables-bundle/datatables.min.css') 
    ] 
}) 
@Injectable() 
export class DatatableComponent implements OnInit, OnDestroy { 

    @Input() public options: any; 
    @Input() public filter: any; 
    @Input() public detailsFormat: any; 

    @Input() public paginationLength: boolean; 
    @Input() public columnsHide: boolean; 
    @Input() public tableClass: string; 
    @Input() public width = '100%'; 

    public datatableInitialized: boolean; 

    public subscription: Subscription; 

    constructor(private el: ElementRef, private tablesService: IBOsService) { 
     this.tablesService.refreshTable$.subscribe((tableParams) => { 
       this.filterData(tableParams); 
      } 
     ); 

     this.tablesService.initTableData$.subscribe(() => { 
       if (!this.datatableInitialized) { 
        log.info('Starting script import promise'); 

        Promise.all([ 
         System.import('script-loader!my-plugins/datatables-bundle/datatables.min.js') 
        ]).then(values => { 
         log.data('success', JSON.stringify(values)); 
         this.render(); 
        }, reason => { 
         log.error('error', JSON.stringify(reason)); 
        }); 
       } 
      } 
     ); 
    } 

    ngOnInit() { 
    } 

    render() { 
     log.info('Starting render!'); 

     const element = $(this.el.nativeElement.children[0]); 
     let options = this.options || {}; 

     log.info('1 render!'); 

     let toolbar = ''; 
     if (options.buttons) { 
      toolbar += 'B'; 
     } 
     log.info('2 render!'); 

     if (this.paginationLength) { 
      toolbar += 'l'; 
     } 

     if (this.columnsHide) { 
      toolbar += 'C'; 
     } 

     log.info('3 render!'); 

     if (typeof options.ajax === 'string') { 
      const url = options.ajax; 
      options.ajax = { 
       url: url, 
       // complete: function (xhr) { 
       // 
       // } 
      }; 
     } 

     log.info('4 render!'); 

     options = $.extend(options, { 

      'dom': '<\'dt-toolbar\'<\'col-xs-12 col-sm-6\'f><\'col-sm-6 col-xs-12 hidden-xs text-right\'' + toolbar + '>r>' + 
      't' + 
      '<\'dt-toolbar-footer\'<\'col-sm-6 col-xs-12 hidden-xs\'i><\'col-xs-12 col-sm-6\'p>>', 
      oLanguage: { 
       'sSearch': `<span class='input-group-addon'><i class='glyphicon glyphicon-search'></i></span>`, 
       'sLengthMenu': '_MENU_' 
      }, 
      'autoWidth': false, 
      retrieve: true, 
      responsive: true, 
      initComplete: (settings, json) => { 
       element.parent() 
        .find('.input-sm') 
        .removeClass('input-sm') 
        .addClass('input-md'); 
      } 
     }); 

     log.info('5 render! element', JSON.stringify(element)); 
     log.info('5.1 render! options', JSON.stringify(options)); 

     const _dataTable = element.DataTable(options); 

     log.info('5.2 render! _dataTable', JSON.stringify(_dataTable)); 

     if (this.filter) { 
      // Apply the filter 
      element.on('keyup change', 'thead th input[type=text]', function() { 
       console.log('searching?'); 
       _dataTable 
        .column($(this).parent().index() + ':visible') 
        .search(this.value) 
        .draw(); 
      }); 
     } 

     log.info('6 render!'); 

     if (!toolbar) { 
      element.parent().find('.dt-toolbar') 
       .append(
        '<div class="text-right">' + 
        '<img src="assets/img/logo.png" alt="SmartAdmin" style="width: 111px; margin-top: 3px; margin-right: 10px;">' + 
        '</div>' 
       ); 
     } 

     log.info('7 render!'); 

     if (this.detailsFormat) { 
      const format = this.detailsFormat; 
      element.on('click', 'td.details-control', function() { 
       const tr = $(this).closest('tr'); 
       const row = _dataTable.row(tr); 
       if (row.child.isShown()) { 
        row.child.hide(); 
        tr.removeClass('shown'); 
       } else { 
        row.child(format(row.data())).show(); 
        tr.addClass('shown'); 
       } 
      }); 
     } 

     log.info('8 render!'); 

     this.datatableInitialized = true; 
    } 

    filterData(tableParams) { 
     console.log('reloading DT... With these parameters: ' + JSON.stringify(tableParams)); 

     const element = $(this.el.nativeElement.children[0]); 
     const table = element.find('table.dataTable'); 

     log.data('current table element is: ', JSON.stringify(table)); 

     Object.keys(tableParams).forEach(function (key) { 
      log.warn('current key: ', JSON.stringify(key)); 
      table.DataTable().column(`${key}:name`).visible(tableParams[key]); 
     }); 

     table.DataTable().ajax.reload(); 
    } 

    ngOnDestroy() { 
     if (this.subscription) { 
      this.subscription.unsubscribe(); 
     } 
    } 
} 

你會看到我用日誌侵入了組件,它幫助我瞭解組件在哪裏失敗。

完全控制檯登錄:

enter image description here

有趣的信息:

如果我稱之爲filterData(tableParams)方法... DataTable中呈現,沒有任何問題。

這告訴我兩件事情:

  1. DataTable()不是問題。
  2. 這個問題只在第一次渲染,然後,在更新時,我沒有遇到任何問題。

我爲我的文字的牆非常抱歉......但我做了一些福爾摩斯由我自己,無法找到解決方案。

如果你需要澄清或更多的細節讓我知道。

在此先感謝!

更新:

調試天后,我發現錯誤的可能來源:

enter image description here

的事情是,snull

也許有人對DataTables有更多的經驗或遇到這個問題可能會給我提示發生了什麼。

我會在這裏調試...;)

更新2:

經過調試,我發現,數據表不使第一Ajax調用

我正在使用服務器端數據表,在POST中使用Ajax調用。

這裏是我的options對象的代碼:

this.options = { 
    dom: 'Bfrtip', 
    processing: true, 
    serverSide: true, 
    pageLength: 20, 
    searchDelay: 1200, 
    ajax: { 
     url: this.jsonApiService.buildURL('/test_getUsers.php', 'remote'), 
     type: 'POST', 
     data: function (d) { 
      Object.assign(d, IBOsTable.params); 
      log.data('DT options obj. New params are: ', JSON.stringify(IBOsTable.params)); 
      return d; 
     } 
    }, 
    columns: this.initColumns, 
}; 

不是讓Ajax調用在初始化,但它使得它table.DataTable().ajax.reload();

這告訴我,代碼不是不正確或損壞(上reload()作品就像一個魅力)...

我還沒有完全undesrtanding爲什麼這個數據表的初始化是不工作...但是,我相信我已經夠接近了!

+0

如果是S定義?我沒有看到該代碼 – Bindrid

+0

@Bindrid嗨! 's'不是行列式。我發現我的DT沒有進行第一次Ajax調用,因此沒有實際的數據進行渲染,這就是錯誤發生的原因。這裏的問題是找出爲什麼不做第一個Ajax調用。乾杯! ;) – SrAxi

回答

0

我終於找到了錯誤的來源!

如果你看過我的更新你會發現我想通了,我的數據表並沒有使第一Ajax調用,但reload()是完美的工作:

這是因爲在初始化JavaScript錯誤不允許進行Ajax調用。提示:TypeError:無法讀取空值的屬性'nodeName'。

speaking to Allan (from DataTables)之後,他給我提示錯誤可能是由於thead的列數不等於tbody的列數引起的。

所以我查了一下.html,發現我有一些空的<thead><tfoot>標籤。我評論他們......並且工作!

enter image description here

我已經跑了個遍每一個可能的解決方案:

  • 依賴
  • 實例化的數據表服務器端
  • 的角2應用
  • 許多不同的方式中的jQuery庫在代碼中改變方法:TypeScript,jQuery,Ng2等...

最後,我只需要清除我的DataTable加載到的div,以避免此問題。

有趣的事實:隨着該.HTML我的應用程序工作了3/4個月,沒有任何問題,用數據表沒有問題到現在爲止...

相關問題