Drum machine: keypress events

Tell us what’s happening:

I’ve been working on the drum machine project (linked below) for a while now, and have had quite a bit of trouble. Through searching the forum and other resources I’ve managed to get audio to play by clicking on the element, but I have been unable to handle the keymapping feature.
(I have not implemented any CSS so far, and have only worked on 1 drumpad element.)

Your code so far
https://codepen.io/importhuman/pen/xxEGBPP

Your browser information:

User Agent is: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0.

Challenge: Build a Drum Machine

Link to the challenge:

There are a few different ways of doing it.

In the handler function, you can use event.key to get the key pressed, it corresponds to the id on the audio element (in lower case). So you can use that to get to the audio element.

const key = event.key.toUpperCase();
const sound = document.getElementById(key);
1 Like

@lasjorg Thank you very much! This seems to be working fine, and I’ve tried it with the next element as well. However, the name that shows up on clicking the element doesn’t seem to be working with the keypress despite using the same setState method, and I noticed onClick requires 2 clicks to play audio. Can you help with that?

I think it has to do with the props you are passing down and updating their values in the setState.

You don’t need the key or the name inside the child, so I would remove the props. The name should be inside a single element with the id #display, you can just create an element in the main parent component.

<div id="display">{this.state.name}</div>


As an aside, I would not hardcode the buttons and values inside the DrumPad component. It would be better to use an array of objects (or an object of objects) and map it in the JSX. You have the beginning of that already in the commented out code at the top.

I removed the props as you suggested, which has resolved the 2 clicks issue, but the name still doesn’t show on keypress. I’m working on mapping the array into JSX part.

@lasjorg I’m having an issue in mapping the handleClick and handleKeyPress functions, the remaining elements are being rendered correctly. :sweat_smile:
https://codepen.io/importhuman/pen/xxEGBPP?editors=0010

Remove the braces from the arguments to the handler functions.

1 Like

Thank you :smiley:
Why isn’t the name being displayed on keypress events even when the same setState method has been used? It works on clicking the element, and I’m not using the same method of rendering components as before :sweat_smile:

It is the handler you have attached in componentDidMount to the document that is called when pressing a button, not the onKeyPress you have on the element. So you are not getting any arguments passed to the handler function (other than the event).

As an aside. Technically, you can still call the inline handler by clicking the button so it has focus and then press the corresponding keyboard button and it will fire the inline handler, but that isn’t very useful.

One option might be to get the key that was pressed, use that to get the audio element and then get the parent element. The parent element id is the name.

1 Like

Can you please explain how one would get the audio element from the key and so on? I have managed to solve my issue by modifying the function, but I’d like to know what else could have been done.

In case someone else gets stuck on a similar issue as me and ends up here:
https://codepen.io/importhuman/pen/bGwgoqJ?editors=0010

Doing it like you are, works just fine.

You don’t really need the switch though. The audio element and the parent element already has the information on them as attributes.

1 Like

If you’re talking about the audio & parent in the mapping part, how would I use their attributes with handleKeyPress is what I cannot understand. :no_mouth:

  1. event.key is the key that was pressed. It is in lower case, so you need to uppercase it. Use that for the audio element selector (by id). Now you have a reference to the audio element (and can call play on it as well).

  2. You can get to the parent element id using parentElement.id on the audio element reference.

  handleKeyPress(event, name) {
    const key = event.key.toUpperCase();

    const audioElement = document.getElementById(key);
    const parentElementId = audioElement.parentElement.id;

    this.setState({ key, name: parentElementId });
    audioElement.play();
  }
1 Like