Search code examples
javascripthtmlhtml-tableinnerhtml

Finding logic to address "TypeError: Cannot read properties of undefined (reading 'innerHTML')" possible Null Errors


I have function that reads all the tables created in an HTML and exports a clean .xls that contains all of the tables created (with a space between each table for flavor). Upon executing it for the first time it prompted the following.

"TypeError: Cannot read properties of undefined (reading 'innerHTML')"

I am unable to retrieve a detailed debug as this is happening on a protected IIS server, and only armed with F11 function and the .btn that upon clicking on it does not work. First instinct is that for some reason the following code is possibly running into a null event.

scope.exportToScv = function(){
    var csvTitle = document.getElementsByTagName('title')[0].innerHTML.split(" - ")[1].replace(/\s/g, '');
    var options = { hour12: false };
    var str = ((new Date()).toLocaleString('en-US', options)).replace(/\s/g, "T").replace(/\//g,'').replace(/:/g,'');
    csvTitle = 'Failed' + csvTitle + '.csv';
    var csv = '';
    var ths = document.getElementsByTagName('th');
    for(var i=0; i<ths.length; i++) {
        var kLink = ths[i].getElementsByClassName("k-link")[0];
        if(i === ths.length-1)
            csv += kLink.innerHTML.split('<')[0] + '\r\n';
        else
            csv += kLink.innerHTML.split('<')[0] + ',';
    }
    var trs = document.getElementsByTagName('tr');
    for(var j=0; j < trs.length; j++) {
        if((trs[j].getAttribute("role") == "row").valueOf() && (trs[j].parentNode.tagName == "TBODY").valueOf()){                                   
            for(var k=0; k < trs[j].childNodes.length; k++) {
                if(k === 0)
                    csv += (trs[j]).childNodes[k].childNodes[0].innerHTML + ',';
                else if(k === trs[j].childNodes.length-1)
                    csv += (trs[j]).childNodes[k].innerHTML + '\r\n';
                else if(k === trs[j].childNodes.length-2)
                    csv += (trs[j]).childNodes[k].innerHTML.replace("&gt;",">") + ',';
                else
                    csv += (trs[j]).childNodes[k].innerHTML + ',';
            }
        }
    };

Button Code (May not be relevant, but fires up the calling scope)

<!-- <div style="color: white"> Export To CSV </div> -->
<!-- <label class="switch"> -->
<button type="submit" class="btn export" value="ExportToCsv" ng-model="config.Enabled" ng-click="exportToScv()">Export To CSV</button>
<!-- <span class="slider round"></span> -->
<!-- </label> -->

Trying to think of a simple clean way around this possibly if-Else logic without having to rewrite the whole thing. Thanks all.

Update - as it turns out, it is as I suspected. The table(s) have no title associated to them

<symbol-host-div symbol="sym" runtime-data="::dispCtrl.getRuntimeSymbolData(sym.Name)" style="cursor: default;"><div class="symbol-mouse-drop symbol-host editor-symbol-host multiple ui-droppable" id="Symbol0" title="" style="position:

The title is "" regardless of any number of tables.


Solution

  • this type of problem is usually related to accessing a property of an element that does not yet exist. I suggest you add a condition before accessing the innerHtml property. Since you don't have access to detailed debugging information, it can be helpful to understand which element is returning undefined.

    This line can help you with it.

    var csvTitleElement = document.getElementsByTagName('title')[0];
        var csvTitle = csvTitleElement ? csvTitleElement.innerHTML.split(" - ")[1].replace(/\s/g, '') : '';