Having trouble with Javascript volume property in React (drum machine project)

Drum Machine
This passes all of the tests, however I’m having some real issues adding a volume adjusting feature. I made an adjustVolume function in the parent component that is supposed to pass down the volumeLevel state to the child component. While I’ve tried assigning the audio.volume property to this.props.volumeLevel, I can’t seem to get it to work the way I want it to. I was able to get the volume to change by editing the HandleClick() and HandleKeyDown() functions as follows:

 handleKeyDown = e => {
    if(e.keyCode === this.props.keyTrigger.charCodeAt()) {
      this.audio.play()
      this.audio.currentTime = 0
      this.props.handleDisplay(this.props.id)
      this.audio.volume = 0.2
    }
  }
  
  handleClick = () => {
    this.audio.play()
    this.audio.currentTime = 0
    this.props.handleDisplay(this.props.id)
    this.audio.volume = 0.2
  }

However this isn’t dynamic and I want to be able to slide the volume bar to change the volume. Here is the entire React code I have so far for reference:

const soundBankOne = [{
    keyCode: 81,
    keyTrigger: 'Q',
    id: 'Heater-1',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Heater-1.mp3'
  }, {
    keyCode: 87,
    keyTrigger: 'W',
    id: 'Heater-2',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Heater-2.mp3'
  }, {
    keyCode: 69,
    keyTrigger: 'E',
    id: 'Heater-3',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Heater-3.mp3'
  }, {
    keyCode: 65,
    keyTrigger: 'A',
    id: 'Heater-4',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Heater-4_1.mp3'
  }, {
    keyCode: 83,
    keyTrigger: 'S',
    id: 'Clap',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Heater-6.mp3'
  }, {
    keyCode: 68,
    keyTrigger: 'D',
    id: 'Open-HH',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Dsc_Oh.mp3'
  }, {
    keyCode: 90,
    keyTrigger: 'Z',
    id: "Kick-n'-Hat",
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Kick_n_Hat.mp3'
  }, {
    keyCode: 88,
    keyTrigger: 'X',
    id: 'Kick',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/RP4_KICK_1.mp3'
  }, {
    keyCode: 67,
    keyTrigger: 'C',
    id: 'Closed-HH',
    url: 'https://s3.amazonaws.com/freecodecamp/drums/Cev_H2.mp3'
  },
];

class DrumPad extends React.Component {
  
  componentDidMount() {
    document.addEventListener('keydown', this.handleKeyDown)
    //window.focus()
  }
  
  componentWillUnmount() {
    document.removeEventListener('keydown', this.handleKeyDown)
  }
  
  handleKeyDown = e => {
    if(e.keyCode === this.props.keyTrigger.charCodeAt()) {
      this.audio.play()
      this.audio.currentTime = 0
      this.props.handleDisplay(this.props.id)
    }
  }
  
  handleClick = () => {
    this.audio.play()
    this.audio.currentTime = 0
    this.props.handleDisplay(this.props.id)
  }
  
  render() {
    return(
      <div id="board">
      <div 
        className="drum-pad" 
        id={this.props.id}
        onClick={this.handleClick}
        >
        <p>{this.props.keyTrigger}</p>
        <audio className="clip"
          ref={ref => this.audio = ref}
          src={this.props.url} 
          id={this.props.keyTrigger}
        />
      </div>
        </div>
    );
  }
}

class Controls extends React.Component {
 
  render() {
    return(
      <div id="controls">
        <div>
        <h2>Volume</h2>
         <input type="range" min="0" max="1" step="0.01"/>
        </div>
        </div>
    );
  }
}


class App extends React.Component {
  constructor(props) {
    super(props)
    this.adjustVolume = this.adjustVolume.bind(this);
    this.state = {
      display: 'Click or Press Key',
      volumeLevel: 0.4
    }
  }
  
  adjustVolume = e => {
    this.setState({
        volumeLevel: e.target.value
      });
  }
  
  handleDisplay = display => this.setState({ display })
  
  render() {
    return(
    <div id="drum-machine">
        <div id="display">{this.state.display}</div>
        <div id="drum-pads">
        {soundBankOne.map(s => (
          <DrumPad
            id={s.id}
            keyTrigger={s.keyTrigger}
            url={s.url}
            handleDisplay={this.handleDisplay}
            />
          ))}</div>
        <Controls 
          value={this.state.volumeLevel} 
          onChange={this.adjustVolume} 
          />
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));

Any help would be greatly appreciated!

Hello,
It would be really helpful if you could post a link to your codepen. I do see you pass props to your Control Component from your app container. What I don’t see is where your input(slider) on your control component uses the props that is passed into it.

Ex:
 <input type="range" min="1" max="100" value={value} class="slider" id="myRange" >;

console.log(the input slide see if you see any changes.

https://codepen.io/tracer223/pen/oaEvEe?editors=0010

There’s a link at the top of the post (labeled Drum Machine) but it’s probably too small to notice. Here’s a different link to my codepen. Thanks!

How did you resolve this issue?

hey man I love this! After I learn html/css/js I wanted to build something similar. Do you go straight to react to learn how to do this?

Was this ever resolved? I’m running into the same issue with my project.

Hey not sure if you ever worked this out but I figured out a fix that worked for me. First a made a separate slider using this tutorial.

https://www.w3schools.com/howto/howto_js_rangeslider.asp

Then learn how to console log the value of that slider.

Then you pass that value of slider (with a min of 0 and max of 100) to the state of react // or Redux Whatever you are using.

You can use a handleChangeMethod as a onChange for the range input you define. This will update that state when you click on slider.

Finally in your onClick for the button, set the audio of that button manually with java script of that button with the audio from state. I had to use native java-script though. Something like this. document.getElementById(id).volume = (this.props.volume)

So all together should look something like this.


//bind function in constructor 
constructor(props) {
        super(props)
        this.handleChange = this.handleChange.bind(this);
}
//this is  handleChange function definition
 handleChange(event) { //event is how you get slider value use event.target.value to get value of slider aka volume
        this.props.currentVolumeDispatch(event.target.value); // or set your state here if just using react
            }

//this is handleClick function
handleClick() {
     id = document.getElementById('Q') //  you can figure out logic later to select the audio element in the button that was clicked instead of using this
  document.getElementById(id).volume = this.props.volume // or state if using just React
 playAudio(id); // this plays audio of your selcted element
}

//this will be in react REnder()
 <div className = "slidecontainer">
                <input type="range" min="0" max = "100"  value = {this.props.volume}  onChange = {this.handleChange} classNameName="slider2" id = "myRange"/>
                </div>
//use state instead of props if using just react

Anyways hope this is helpful to someone in the future worked for me!

Additionally i learned cannot set Volume with HTML has to be done with javascript, I am sure there is way with Jquery but could not for the life of me figure that one out lol.