skip to Main Content

HTML and Javascript newbie here. I am trying to make a webpage that allows you to specify the number of times a random number will be presented to you (random number will be between bounds that you specify) and you attempt to hold the spacebar for the matching amount of time. Each time you lift the spacebar for a trial, it progresses to the next trial. with a 5 second count down first. This works the first time, but after lifting the key, it seems that the functions to transition to the next trial are not executing. The output records the key holds, but there is no count down and the page does not update the trial number, or create a new random number within the bounds. Any help would be greatly appreciated!

I have tried googling and looking on forums, best I can find is that the function is throwing an: "index.html:92 Uncaught TypeError: Cannot set properties of null (setting ‘textContent’)" error, but I don’t know if this is the real cause, or how to correct it.

P.S. If anyone could also explain why the time recorded is 0.012 seconds when held for 5-10 seconds, that would be swell. But this is secondary.

let trialsLeft;
let lowerBound;
let upperBound;
let trialNumber = 1;
let csvContent = "data:text/csv;charset=utf-8,Trial,Durationn";
let spacebarDownTime;
let spacebarUpTime;

/*
function startCountdown() {
    let countdownElement = document.getElementById('countdown');
    let count = 5;
    countdownElement.textContent = count;

    let timer = setInterval(() => {
        count--;
        countdownElement.textContent = count;

        if (count <= 0) {
            clearInterval(timer);
            displayRandomNumber();
        }
    }, 1000);
}
*/

function startCountdown() {
  let countdownElement = document.getElementById('countdown');
  let count = 5;
  countdownElement.textContent = 5;

  let timer = setInterval(() => {
    count--;
    countdownElement.textContent = count;

    if (count <= 0) {
      clearInterval(timer);
      displayRandomNumber();
    }
  }, 1000);
}

/*
function displayRandomNumber() {
    let randomNumber = Math.floor(Math.random() * (upperBound - lowerBound + 1)) + lowerBound;
    document.getElementById('page2').innerHTML = `  <h2>Trial number: ${trialNumber} </h2>
                                                    <h2>Number of seconds to hold the spacebar: ${randomNumber}</h2>
                                                    <p>Press and hold the spacebar to record the duration.</p>`;
    document.addEventListener('keydown', handleKeyDown);
}
*/
function displayRandomNumber() {
  document.getElementById('page2').style.display = 'block'; // Ensure page2 is displayed
  let randomNumber = Math.floor(Math.random() * (upperBound - lowerBound + 1)) + lowerBound;
  document.getElementById('page2').innerHTML = `
                <h2>Trial number: ${trialNumber}</h2>
                <h2>Number of seconds to hold the spacebar: ${randomNumber}</h2>
                <p>Press and hold the spacebar to record the duration.</p>
            `;

  document.addEventListener('keydown', handleKeyDown); // Add event listener
}

/*
function handleKeyDown(event) {
    if (event.key === ' ') {
        spacebarDownTime = new Date().getTime();
        document.addEventListener('keyup', handleKeyUp);
    }
}
*/
function handleKeyDown(event) {
  if (event.key === ' ') {
    spacebarDownTime = new Date().getTime(); // Record time of key press
    document.addEventListener('keyup', handleKeyUp); // Add keyup listener
  }
}

/*
function handleKeyUp(event) {
    document.removeEventListener('keydown', handleKeyDown);
    if (event.key === ' ') {
        spacebarUpTime = new Date().getTime();
        let duration = spacebarUpTime - spacebarDownTime;
        if (duration > 0) { // Only save duration if it's a positive value
            saveData(trialNumber, spacebarDownTime);
            saveData(trialNumber, spacebarUpTime);
        }
        nextTrial();
        document.removeEventListener('keyup', handleKeyUp);
    }
}
*/

function handleKeyUp(event) {
  if (event.key === ' ') {
    spacebarUpTime = new Date().getTime(); // Record time of key release
    let duration = spacebarUpTime - spacebarDownTime;
    if (duration > 0) {
      saveData(trialNumber, duration);
    }
    nextTrial(); // Move to the next trial
    document.removeEventListener('keyup', handleKeyUp); // Remove keyup listener
  }
}

function saveData(trialNumber, duration) {
  csvContent += `${trialNumber},${duration/1000} seconds.n`;
}

/*
function nextTrial() {
    trialNumber++;
    if (trialNumber <= trialsLeft) {
        //displayCountdown();
        startCountdown();
    } else {
        displayExportButton();
    }
}
*/

function nextTrial() {
  trialNumber++;
  if (trialNumber <= trialsLeft) {
    displayCountdown(); // Correct function call to start countdown
  } else {
    displayExportButton(); // Show export options if trials are completed
  }
}

/*
function displayCountdown() {
    document.getElementById('page2').style.display = 'none';
    document.getElementById('page1').style.display = 'none';
    document.getElementById('countdown').textContent = '5';
    document.getElementById('page2').style.display = 'block';
    startCountdown();
}
*/

function displayCountdown() {
  document.getElementById('page1').style.display = 'none'; // Hide page1
  document.getElementById('page2').style.display = 'block'; // Ensure page2 is visible
  startCountdown(); // Initiate countdown
}

function displayExportButton() {
  document.getElementById('page1').style.display = 'none';
  document.getElementById('page2').style.display = 'none';
  document.getElementById('exportContainer').style.display = 'block';
}

function exportData() {
  const encodedUri = encodeURI(csvContent);
  const link = document.createElement("a");
  link.setAttribute("href", encodedUri);
  link.setAttribute("download", "key_press_data.csv");
  document.body.appendChild(link);
  link.click();
}

function resetPage() {
  location.reload(); // Reload the page to reset everything
}

document.getElementById('startButton').addEventListener('click', function() {
  trialsLeft = parseInt(document.getElementById('numTrials').value);
  lowerBound = parseInt(document.getElementById('lowerBound').value);
  upperBound = parseInt(document.getElementById('upperBound').value);

  if (isNaN(trialsLeft) || isNaN(lowerBound) || isNaN(upperBound)) {
    alert('Please enter valid numbers');
    return;
  }

  if (lowerBound >= upperBound) {
    alert('Upper bound must be greater than lower bound');
    return;
  }

  displayCountdown();
});

document.getElementById('exportBtn').addEventListener('click', exportData);
document.getElementById('resetBtn').addEventListener('click', resetPage);
body {
  font-family: Arial, sans-serif;
  margin: 0;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}

.container {
  text-align: center;
}

button {
  padding: 10px 20px;
  font-size: 16px;
  cursor: pointer;
  margin-top: 10px;
}

#countdown {
  font-size: 24px;
  margin-bottom: 20px;
}
<div class="container">
  <div id="page1">
    <h2>Enter Details</h2>
    <label for="numTrials">Number of Trials:</label>
    <input type="number" id="numTrials" min="1" required>
    <br>
    <label for="lowerBound">Lower Bound Time (seconds):</label>
    <input type="number" id="lowerBound" min="1" required>
    <br>
    <label for="upperBound">Upper Bound Time (seconds):</label>
    <input type="number" id="upperBound" min="1" required>
    <br>
    <button id="startButton">Start</button>
  </div>

  <div id="page2" style="display: none;">
    <h2>Countdown</h2>
    <div id="countdown">5</div>
  </div>

  <div id="exportContainer" style="display: none;">
    <button id="exportBtn">Export Data</button>
    <br>
    <button id="resetBtn">Reset</button>
  </div>
</div>

2

Answers


  1. This is throwing an error after the the first time because of the following function:

    function displayRandomNumber() {
        document.getElementById('page2').style.display = 'block'; // Ensure page2 is displayed
        let randomNumber = Math.floor(Math.random() * (upperBound - lowerBound + 1)) + lowerBound;
        document.getElementById('page2').innerHTML = `
            <h2>Trial number: ${trialNumber}</h2>
            <h2>Number of seconds to hold the spacebar: ${randomNumber}</h2>
            <p>Press and hold the spacebar to record the duration.</p>
        `;
        document.addEventListener('keydown', handleKeyDown); // Add event listener
    }
    

    When you redefine the innerHTML of page2 you remove this element <div id="countdown">5</div> from the page. Therefore, this line:
    let countdownElement = document.getElementById('countdown'); can’t find any element and this line:
    countdownElement.textContent = 5; throws the error you described:
    index.html:92 Uncaught TypeError: Cannot set properties of null (setting 'textContent')

    I’m not sure if the rest of the code is correct, but fixing this will guide you in the right direction.

    Login or Signup to reply.
  2. Update the content instead of replacing it. The div with the ID="page2" disappears when you update the innerHTML of page2

    Have a page3 and update content and toggle when needed

    <div id="page2" style="display: none;">
      <h2>Countdown</h2>
      <div id="countdown">5</div>
    </div>
    
    <div id="page3" style="display: none;">
      <h2>Trial number: <span id="trial"></span></h2>
      <h2>Number of seconds to hold the spacebar: <span id="random"></span></h2>
      <p>Press and hold the spacebar to record the duration.</p>
    </div>
    

    Additionally only have ONE eventListener per event type on the page

    MOVE document.addEventListener('keydown', handleKeyDown); to outside the function. You need this ONCE per page load so you can delete document.removeEventListener('keyup', handleKeyUp); // Remove keyup listener too

    Same for document.addEventListener('keyup', handleKeyUp); // Add keyup listener

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search