Need help in Drum Machine Project

I am doing my project using pure javascript. I wonder why my project is not passing all test suites.
My codepen is:

Tell me what’s happening, please!!

One thing I notice is here:

      <div class="drum-pad" id="Q">
        <button class="btn btn-primary border border-danger" type="button" id="Q">Q</button>
        <audio class="clip" src='https://s3.amazonaws.com/freecodecamp/drums/Chord_1.mp3' id="Q">
        </audio>
      </div>

You have two things with an id of “Q”. In html, ids must be unique, there can only be one of each.

Thanks, Kevin I removed duplicates still not passing the test suites . Can you please help me in solving this . My codepen is:

OK, when I look at the first failing test, I see:

When I click on a .drum-pad element, the audio clip contained in its child <audio> element should be triggered.

The <audio> element with id=“Q” does not play when the Q .drum-pad is clicked : expected true to be false AssertionError: The <audio> element with id=“Q” does not play when the Q .drum-pad is clicked : expected true to be false

Just for reference, When I look in the repo at the actual test, I see this:


      it(`When I click on a .drum-pad element, the audio clip
      contained in its child <audio> element should be triggered.`, function () {
        assert.isAtLeast(
          audioElements.length,
          9,
          'Audio elements do not exist '
        );
        audioElements.forEach((el) => {
          el.pause();
          __triggerClickEventCaller(el.parentElement);
          assert.isFalse(
            el.paused,
            'The <audio> element with id="' +
              el.id +
              '" does not play when the ' +
              el.id +
              ' .drum-pad is clicked '
          );
        });
      });

So, it is going through each audio element, making sure it is paused, then clicking it, and then seeing if that element is still paused.

When I look in your code, I see this your an element’s HTML:

         <button class="btn btn-primary border border-danger drum-pad" type="button" id="1" onclick="afterclick('Q')">
            Q
            <audio class="clip" src='https://s3.amazonaws.com/freecodecamp/drums/Chord_1.mp3' id="Q"  >
            </audio>
         </button>

and in your JS:

function afterclick(str){
  var audios=document.getElementsByClassName("clip");
  var audio=new Audio();
  for(let i=0;i<audios.length;i++){
    if(str==audios[i].getAttribute("id")){
      audio.src=audios[i].getAttribute("src");
      document.getElementsByClassName("audio")[0].innerHTML=audio.src;
      audio.play();
        
    }
  }
}

I have a few questions, but the first would be why are you creating a new audio element. The HTML element already has an audio element - you can just play that. I was able to get the test to pass by doing that.

Next I would wonder if after you find your matching element, if you need to keep searching with your for loop. This isn’t breaking anything, but it’s good to start thinking like this.

Another way to think about it would be to, instead of passing in the letter, pass in the element itself:

onclick="afterclick(this)"

Now you are passing in the element. You can select the audio node from among the childNodes property and activate the play method on it. Now it’s a one line function.


Looking at failing test #6, it looks like you have a similar issue with creating a new audio instead of using the existing one.

In terms of simplifying, what if those buttons had meaningful ids, like “drum-key-Q”. Then you could use the keycode to select and press the right button. I don’t think you need a for loop there or the if. I don’t think you need that obj there since everything is encoded in your HTML. There are ways to build this that would need that (like if you were building your buttons programmatically) but I don’t think you’re doing that here. I might be wrong, it’s just and quick observation.


For the last one, you are putting this all in a textarea. This is for entering and editing text. We just need to display it.

The test says:

      it(`When a .drum-pad is triggered, a string describing the
      associated audio clip is displayed as the inner text of the #display
      element (each string must be unique).`, function () {
        let displayText = [];
        drumPads.forEach((pad) => {
          __triggerClickEventCaller(pad);
          displayText.push(document.getElementById('display').innerText);
        });
        displayText = displayText.filter(
          (str, i) => displayText[0] === displayText[i]
        );
        assert.isTrue(
          displayText.length === 1,
          'Each time a drum pad is triggered, a unique string should ' +
            'be displayed in the element with the id "display"'
        );
      });

So, it is looking at the value gotten by:

document.getElementById('display').innerText

When I look at the text of that user story, I see:

User Story #7: When a .drum-pad is triggered, a string describing the associated audio clip is displayed as the inner text of the #display element (each string must be unique).

I see that your code has:

     document.getElementsByClassName("audio")[0].innerHTML=audio.src;

Do you see a difference between what you were asked to do and what you did?