skip to Main Content

I’m pretty new to this, and I’m having trouble getting the output I’m looking for. I have a web page where I’d like to display my CSV in a nice looking table. The output is not being displayed on the web page at all when I access the local port. When I go to inspect and then the network tab, I can see that the GET to /data is working. It returns 200, type JSON, and I see the JSON body. Where is the point that’s going wrong? Inspect shows JSON returned and logs show ‘sending data in res.json’ but no ‘fetch’ (from script.js). Clearly never got there, but why is that and how can I fix it?

script.js:

// Function to fetch CSV data from the server and render it as a table
const fetchAndRenderCSV = async () => {
    try {
        console.log('trying fetch /data')
        const response = await fetch('/data');
        console.log('Response is: ' + response)
        const csvData = await response.json();
        console.log(csvData)
        renderCSVTable(csvData);
    } catch (error) {
        console.error('Error fetching CSV data:', error);
    }
};

// Function to render CSV data as a table
const renderCSVTable = (data) => {
    const tableContainer = document.getElementById('csvTableContainer');
    const tableHTML = generateTableHTML(data);
    tableContainer.innerHTML = tableHTML;
};

// Function to generate HTML for the table
const generateTableHTML = (data) => {
    let tableHTML = '<table>';
    // Assuming the first row contains headers
    tableHTML += '<tr>';
    for (let i = 0; i < data[0].length; i++) {
        tableHTML += `<th>${data[0][i]}</th>`;
    }
    tableHTML += '</tr>';

    // Add rows for each data entry (excluding the header row)
    for (let i = 1; i < data.length; i++) {
        tableHTML += '<tr>';
        for (let j = 0; j < data[i].length; j++) {
            tableHTML += `<td>${data[i][j]}</td>`;
        }
        tableHTML += '</tr>';
    }

    tableHTML += '</table>';
    return tableHTML;
};

const submitGuess = async () => {
try {
    // Clear result and error messages
    resultMessage.textContent = '';
    errorMessage.textContent = '';

    const inputValue = userInput.value.trim();
    if (inputValue === '') {
        errorMessage.textContent = 'Please enter a name before submitting.';
        return;
    }

    const response = await fetch('/handleInput', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({ userInput: inputValue }),
    });

    const data = await response.json();

    if (data.isCorrect) {
        resultMessage.textContent = 'Correct answer!';
        resultMessage.classList.add('correct-answer');
    } else {
        // Shake animation on incorrect guess
        userInput.classList.add('shake');

        // Remove the 'shake' class after the animation ends
        userInput.addEventListener('animationend', () => {
            userInput.classList.remove('shake');
        });

        resultMessage.textContent = 'Incorrect answer.';
        resultMessage.classList.remove('correct-answer'); // Remove the class if present
    }

    userInput.value = '';
} catch (error) {
    console.error('Error:', error);
}
};

// Call the function to fetch and render CSV data when the page loads
console.log('fetch')
fetchAndRenderCSV();

styles.css:

body {
  font-family: Arial, sans-serif;
  text-align: center;
}

#game {
  margin: 20px auto;
  max-width: 400px;
}

#word {
  font-size: 2em;
  margin-bottom: 20px;
}

#guess {
  padding: 5px;
  font-size: 1.2em;
  width: 100px;
  margin-bottom: 10px;
}

#feedback {
  margin-top: 20px;
  font-weight: bold;
}

@keyframes shake {
  0% {
    transform: translateX(0);
  }
  25% {
    transform: translateX(-5px);
  }
  50% {
    transform: translateX(5px);
  }
  75% {
    transform: translateX(-5px);
  }
  100% {
    transform: translateX(0);
  }
}

.shake {
  animation: shake 0.4s ease-in-out;
}

index.html

<h1>Guess</h1>

<div id="csvTableContainer"></div>
<!-- This is where the table will be rendered -->

<form id="guessForm">
  <label for="userInput">Enter Guess:</label>
  <input type="text" id="userInput" name="userInput" required>
  <button type="button" onclick="submitGuess()" id="submitButton">Submit</button>
</form>

<button onclick="playAgain()" id="playAgainButton">Play Again</button>

<!-- Result message with inline style for correct answer -->
<p id="resultMessage" style="color: green;"></p>

<!-- Error message -->
<p id="errorMessage" style="color: red;"></p>

My server.js:

const puppeteer = require('puppeteer');
const fs = require('fs');
const Papa = require('papaparse');
// const Parse = require('parse');
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const { spawn } = require('child_process');

const app = express();
const port = 3000;

app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());

let isCorrect = false;
let answer, filePath;

app.get('/data', (req, res) => {
    try {
        // Read CSV file
        const csvData = fs.readFileSync(filePath, 'utf8');

        // Parse CSV data
        const parsedData = Papa.parse(csvData, { header: true }).data;

        // Send parsed CSV data as JSON
        console.log('sending data in res.json')
        const ret = res.json(parsedData);
        // console.log(ret)
    } catch (error) {
        console.error('Error reading or parsing CSV file:', error);
        res.status(500).send('Internal Server Error');
    }
});


app.listen(port, () => {
    console.log(`Server is running at http://localhost:${port}`);
    generateCorrectAnswer();
    console.log('The correct answer is: ', answer)
    console.log('filePath is: ' + filePath)
    checkFileExists(filePath)
    readAndParseCSV(filePath);
});

2

Answers


  1. It looks like you weren’t actually calling your fetchAndRenderCSV() function. In the below snippet I modified the function a little bit to digest a CSV-type input (instead of the pre-processed JSON) and at the end of the snippet I actually call the rendering function:

    // Function to fetch CSV data from the server and render it as a table
    const fetchAndRenderCSV = async () => {
        try {
            console.log('trying fetch /data')
            const csvText = await fetch('https://support.staffbase.com/hc/en-us/article_attachments/360009197031').then(r=>r.text());
            let csvData = Papa.parse(csvText,{header:false,skipEmptyLines:true}).data;
            renderCSVTable(csvData);
        } catch (error) {
            console.error('Error fetching CSV data:', error);
        }
    };
    
    // Function to render CSV data as a table
    const renderCSVTable = (data) => {
        const tableContainer = document.getElementById('csvTableContainer');
        const tableHTML = generateTableHTML(data);
        tableContainer.innerHTML = tableHTML;
    };
    
    // Function to generate HTML for the table
    const generateTableHTML = (data) => {
        let tableHTML = '<table>';
        // Assuming the first row contains headers
        tableHTML += '<tr>';
        for (let i = 0; i < data[0].length; i++) {
            tableHTML += `<th>${data[0][i]}</th>`;
        }
        tableHTML += '</tr>';
    
        // Add rows for each data entry (excluding the header row)
        for (let i = 1; i < data.length; i++) {
            tableHTML += '<tr>';
            for (let j = 0; j < data[i].length; j++) {
                tableHTML += `<td>${data[i][j]}</td>`;
            }
            tableHTML += '</tr>';
        }
        tableHTML += '</table>';
        return tableHTML;
    };
    
    fetchAndRenderCSV();
    body {
      font-family: Arial, sans-serif;
      text-align: center;
    }
    
    #game {
      margin: 20px auto;
      max-width: 400px;
    }
    
    #word {
      font-size: 2em;
      margin-bottom: 20px;
    }
    
    #guess {
      padding: 5px;
      font-size: 1.2em;
      width: 100px;
      margin-bottom: 10px;
    }
    
    #feedback {
      margin-top: 20px;
      font-weight: bold;
    }
    
    @keyframes shake {
      0% {
        transform: translateX(0);
      }
      25% {
        transform: translateX(-5px);
      }
      50% {
        transform: translateX(5px);
      }
      75% {
        transform: translateX(-5px);
      }
      100% {
        transform: translateX(0);
      }
    }
    
    .shake {
      animation: shake 0.4s ease-in-out;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.4.1/papaparse.min.js"></script>
    <h1>Guess</h1>
    
    <div id="csvTableContainer"></div>
    <!-- This is where the table will be rendered -->
    
    <form id="guessForm">
      <label for="userInput">Enter Guess:</label>
      <input type="text" id="userInput" name="userInput" required>
      <button type="button" onclick="submitGuess()" id="submitButton">Submit</button>
    </form>
    
    <button onclick="playAgain()" id="playAgainButton">Play Again</button>
    
    <!-- Result message with inline style for correct answer -->
    <p id="resultMessage" style="color: green;"></p>
    
    <!-- Error message -->
    <p id="errorMessage" style="color: red;"></p>

    I also modified the fetch-URL in order to have a workable snippet here in SO.

    Login or Signup to reply.
  2. You certainly need to include submitGuess() to fire off the whole process.

    You should create smaller reduced cases for the best answers.

    You may find constructing DOM nodes easier with methods like:

    const apiEndpoint = "https://jsonplaceholder.typicode.com/users";
    const tableContainer = document.getElementById('csvTableContainer');
    const parser = new DOMParser();
    
    const submitGuess = () => {
      fetchAndRenderCSV();
    };
    
    const playAgain = () => {
      tableContainer.querySelector("table").remove();
    };
    
    const fetchAndRenderCSV = async () => {
    
        const response = await fetch(apiEndpoint);
        const jsonData = await response.json();
        renderTable(jsonData);
    
    };
    
    const renderTable = (jsonData) => {
    
        // create the DOM node
        const table = parser.parseFromString(`<table>
          <thead>
            <th>username</th>
            <th>email</th>
            <th>website</th>
          </thead>
          <tbody>
          </tbody>
        </table>`, "text/html");
        
        // a reference to where rows should be inserted
        const insertionPoint = table.body.firstChild.querySelector("tbody");
       
        jsonData.forEach(user => {
           
           // construct row from data
           const row = `<tr>
               <td>${user.username}</td>
               <td>${user.email}</td>
               <td>${user.website}</td>
           </tr>
           `;
          
           // inject row into table
           insertionPoint.insertAdjacentHTML("beforeend", row);       
           
        });
          
        // now inject the entire table into page
        tableContainer.append(table.body.firstChild);
    
    };
    table, th, td {
      border: 1px solid;
    }
    
    thead {
      background-color: gray;
      color: white;
    }
    <button type="button" onclick="submitGuess()" id="submitButton">fetch and render</button>
    <button type="reset" onclick="playAgain()" id="playAgainButton">reset</button>
    
    <div id="csvTableContainer"></div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search