Is there a way to fix Undefined data in table cells?

29 Views Asked by At

I'm reading an XML file and displaying it on a webpage. I'm using a JS script which reads the XML file and displays the information in a table. However, when the page loads the information inside the cells shows "UNDEFINED". The table should display the person's name and hearing room information.

I have tried the top solution from this stack overflow article: How to make JavaScript execute after page load?

I have checked for spelling mistakes and the structure of my XML file and read several other articles on stack overflow but with no success.

My JS script:

<!DOCTYPE html>
<html lang="en">
    
<head>
    <meta charset="utf-8"/>
    <title></title>
    <script>
        var client;
        if (window.XMLHttpRequest)
        {
            client = new XMLHttpRequest();
        }
        else 
        {
            client = new ActiveXObject("Microsoft.XMLHTTP");
        }
        client.open('GET', 'TestData.xml', true);

        
        
        client.onload = function()  // Function to run when the file loads
        {
            // get the response XML
            var xmlDoc = client.responseXML;

            // get the list
            var hearings = xmlDoc.getElementsByTagName("hr");

            
            // get the container where you want to embed the table
            var container = document.getElementById("container");

            // Create a table and put the data inside it
            var tableString = "<table border = '1'>";
                for (i = 0; i < hearings.length; i++)
                {
                    tableString += "<tr><td>";
                    tableString += hearings[i].getElementsByTagName("name")[0].childNodes[0].nodValue;
                    tableString += "<tr><td>";
                    tableString += hearings[i].getElementsByTagName("hearing_room")[0].childNodes[0].nodValue;
                    tableString += "<tr><td>";
                    
                }
                tableString +="</table>";

                // append the table to the container
                container.innerHTML = tableString;
        }

        client.send();
    

    </script>   

    
</head>

<body>
    
    <h1></h1>
    
    <div id="container"></div>
    
</body>

</html>

My XML document:

<?xml version="1.0" ?>
<hearing name="hearing_schedule">
    <hr>
        <name>Michelle</name>
        <hearing_room>M028</hearing_room>
    </hr>
    <hr>
        <name>Matthews</name>
        <hearing_room>M028</hearing_room>
    </hr>
   <hr>
        <name>Anita</name>
        <hearing_room>M028</hearing_room>
    </hr>
</hearing>
2

There are 2 best solutions below

0
This Guy On

Try a different selector, since you only expect one of each element per </h r>, you should use a single selector, rather than a list selector.

so, you should be able to use querySelector( )

var tableString = "<table border = '1'>";
for (i = 0; i < hearings.length; i++) {
  tableString += "<tr><td>";
  tableString += hearings[i].querySelector("#name").innerText;
  tableString += "<tr><td>";
  tableString += hearings[i].querySelector("hearing_room").innerText;
  tableString += "<tr><td>";

}

0
ThW On

You need to avoid accessing the property on the undefined object and define a fallback.

const foo = undefined;

// operator "?." avoids accessing undefined properties
console.log(foo?.bar);
// use the "||" operator
console.log(foo?.bar || 'fallback');

Browsers now support the fetch() API. This reduces the needed source and it can be used with async/await.

Query selector allows to use CSS selectors to fetch nodes. Additionally you can use them on element nodes (make the element node the scope of the selector) - avoiding using an counter/index.

Last you should create the DOM elements directly, not as an HTML string.

fetchAndDisplay(
  document.querySelector("#container tbody")
);

// define the function as async - so it can await results of 
// other async calls
async function fetchAndDisplay(container) {
   // wait for the fetched data
   const xml = await fetchXML();
   // clear all nodes inside the target container
   container.textContent = '';
   // fetch all hr elements as an array 
   const hearings = [...xml.querySelectorAll('hr')];
   // append mapped hearings
   container.append(
     ...hearings.map(
     // map hearing into table row
     function (hr) {
       // create row
       const row = document.createElement('tr');
       // create + append cells, use querySelector to fetch content
       row.append(
         createTableCell(hr.querySelector('name')?.textContent || ''),
         createTableCell(hr.querySelector('hearing_room')?.textContent || ''),
       );
       return row;
     }
   ));
}

function createTableCell(textContent) {
   const cell = document.createElement('td');
   cell.textContent = textContent;
   return cell;
}

async function fetchXML() {
  // fetch + parse XML, use string for example
  return (new DOMParser).parseFromString(
    // await fetch('http://...')
    `<?xml version="1.0" ?>
<hearing name="hearing_schedule">
    <hr>
        <name>Michelle</name>
        <hearing_room>M028</hearing_room>
    </hr>
    <hr>
        <name>Matthews</name>
        <hearing_room>M028</hearing_room>
    </hr>
   <hr>
        <name>Anita</name>
        <hearing_room>M028</hearing_room>
    </hr>
</hearing>`,
    'application/xml'
  );
}
<table id="container">
  <tr>
    <th>Name</th>
    <th>Room</th>
  <tr>
  <tbody>
  
  </tbody>
</table>