skip to Main Content

I’m trying to learn JS by following The Odin Project, in which they recommended finishing a tutorial from this Github (JavaScript30), the first one involves triggering a highlight transition whenever a certain box is clicked or the corresponding key is pressed down.

I tried coding it myself first but found out that I’m not receiving the keydown event ever but receiving the click event normally, after reviewing the solution I found that he’s assigning the event to window rather than the box itself.

why isn’t my box receiving the keydown event and why should I assign that to window ?

function togglePlaying(btn) {
  console.log(btn);
  btn.target.classList.toggle('playing');
};
document.querySelectorAll(".key").forEach((key) => {
  console.log(key);
  key.addEventListener('keydown', togglePlaying);
  key.addEventListener('click', togglePlaying);
});
//window.addEventListener('keydown',togglePlaying);
html {
  font-size: 10px;
  background: url('./background.jpg') bottom center;
  background-size: cover;
}

body,
html {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
}

.keys {
  display: flex;
  flex: 1;
  min-height: 100vh;
  align-items: center;
  justify-content: center;
}

.key {
  border: .4rem solid black;
  border-radius: .5rem;
  margin: 1rem;
  font-size: 1.5rem;
  padding: 1rem .5rem;
  transition: all .07s ease;
  width: 10rem;
  text-align: center;
  color: white;
  background: rgba(0, 0, 0, 0.4);
  text-shadow: 0 0 .5rem black;
}

.playing {
  transform: scale(1.1);
  border-color: #ffc600;
  box-shadow: 0 0 1rem #ffc600;
}

kbd {
  display: block;
  font-size: 4rem;
}

.sound {
  font-size: 1.2rem;
  text-transform: uppercase;
  letter-spacing: .1rem;
  color: #ffc600;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>JS Drum Kit</title>
  <link rel="stylesheet" href="style.css">
  <link rel="icon" href="https://fav.farm/🔥" />
</head>

<body>


  <div class="keys">
    <div class="key">
      <kbd>A</kbd>
      <span class="sound">clap</span>
    </div>
    <div class="key">
      <kbd>S</kbd>
      <span class="sound">hihat</span>
    </div>
    <div class="key">
      <kbd>D</kbd>
      <span class="sound">kick</span>
    </div>
    <div class="key">
      <kbd>F</kbd>
      <span class="sound">openhat</span>
    </div>
    <div class="key">
      <kbd>G</kbd>
      <span class="sound">boom</span>
    </div>
    <div class="key">
      <kbd>H</kbd>
      <span class="sound">ride</span>
    </div>
    <div class="key">
      <kbd>J</kbd>
      <span class="sound">snare</span>
    </div>
    <div class="key">
      <kbd>K</kbd>
      <span class="sound">tom</span>
    </div>
    <div class="key">
      <kbd>L</kbd>
      <span class="sound">tink</span>
    </div>
  </div>

2

Answers


  1. Key Events start at the element which has the focus and bubble up the DOM from there.

    The div elements aren’t (and don’t contain any) input elements, elements with a tabindex or anything else what would allow them to hold the focus.

    What’s more, your design implies that it matters which key is pressed while looking at the page, not that any key can be pressed while the focus is on a particular element.

    Binding the keydown listener to the window will capture any keydown event anywhere in the page. You can then use the key property of the event object to determine which key was pressed and use that information to search the DOM for the element you want to toggle the class on.

    Login or Signup to reply.
  2. I made a hashmap of the valid keys which are allowed to be pressed according to the structure of the divs. Then in window keydown listener, if the key pressed was one of those keys, activate its div.

    function togglePlaying(btn) {
      //console.log(btn);
      btn.target.classList.toggle('playing');
    };
    document.querySelectorAll(".key").forEach((key) => {
      key.addEventListener('click', togglePlaying);
    });
    
    const btns = Object.fromEntries(
      [...document.querySelectorAll(".keys .key")].map(k => 
        [k.querySelector("kbd").innerText.toLowerCase(), k]
      )
    );
    
    window.addEventListener('keydown', (e) => {
      let validBtn = btns[e.key.toLowerCase()];
      if (validBtn) {
        validBtn.classList.toggle('playing')
      }
    });
    html {
      font-size: 10px;
      background: url('./background.jpg') bottom center;
      background-size: cover;
    }
    
    body,
    html {
      margin: 0;
      padding: 0;
      font-family: sans-serif;
    }
    
    .keys {
      display: flex;
      flex: 1;
      min-height: 100vh;
      align-items: center;
      justify-content: center;
    }
    
    .key {
      border: .4rem solid black;
      border-radius: .5rem;
      margin: 1rem;
      font-size: 1.5rem;
      padding: 1rem .5rem;
      transition: all .07s ease;
      width: 10rem;
      text-align: center;
      color: white;
      background: rgba(0, 0, 0, 0.4);
      text-shadow: 0 0 .5rem black;
    }
    
    .playing {
      transform: scale(1.1);
      border-color: #ffc600;
      box-shadow: 0 0 1rem #ffc600;
    }
    
    kbd {
      display: block;
      font-size: 4rem;
    }
    
    .sound {
      font-size: 1.2rem;
      text-transform: uppercase;
      letter-spacing: .1rem;
      color: #ffc600;
    }
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>JS Drum Kit</title>
      <link rel="stylesheet" href="style.css">
      <link rel="icon" href="https://fav.farm/🔥" />
    </head>
    
    <body>
    
    
      <div class="keys">
        <div class="key">
          <kbd>A</kbd>
          <span class="sound">clap</span>
        </div>
        <div class="key">
          <kbd>S</kbd>
          <span class="sound">hihat</span>
        </div>
        <div class="key">
          <kbd>D</kbd>
          <span class="sound">kick</span>
        </div>
        <div class="key">
          <kbd>F</kbd>
          <span class="sound">openhat</span>
        </div>
        <div class="key">
          <kbd>G</kbd>
          <span class="sound">boom</span>
        </div>
        <div class="key">
          <kbd>H</kbd>
          <span class="sound">ride</span>
        </div>
        <div class="key">
          <kbd>J</kbd>
          <span class="sound">snare</span>
        </div>
        <div class="key">
          <kbd>K</kbd>
          <span class="sound">tom</span>
        </div>
        <div class="key">
          <kbd>L</kbd>
          <span class="sound">tink</span>
        </div>
      </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search