So I am doing a drum machine project on Freecodecamp, where I am failing this condition.
"
When I click on a .drum-pad element, the audio clip contained in its child element should be triggered.
"
So how do I trigger child element(in this case the audio element,to play the audio) while clicking or pressing the parent element?
I wrote something like this
class Drumset extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this)
}
handleClick(e){
this.inputElement.click()
}
render() {
return (
<div>
<div id="drum-machine" class="containerx box-middle">
<div id="display">
<div class="container">
<div class="row">
<div class="col">
<button type="button" class="drum-pad" id="Heater-1" onClick={this.handleClick}>
Q
<audio
class="clip"
id="Q"
src="https://s3.amazonaws.com/freecodecamp/drums/Heater-1.mp3"
type="audio/mpeg"
></audio>
Well I tried putting the onClick event on inner element, which doesn't work either.
You can get your audio element by searching the DOM and then call .play() on it.
So your onClick handler becomes:
handleClick(e){
const audio = document.getElementById("Q");
audio.play();
}
If you have multiple buttons all with only 1 audio tag inside, you can use one general onClick handler and get the child audio element from the target of the event.
handleClick(e) {
const audio = e.target.children[0];
audio.play();
};
Hello write write this in inner click function
//innerclick function
Const Innerclick(e)=>{
e.stoppropagation()
// do the job here
}
Jsx code html here
Related
I am trying to create a video element in my react component and then set a srcObject to it/ be able to play it after. So basically once the new video renders, I want to do this.video.srcObject = 'a stream' and this.video.play(). Is there something like componentDidMount but for the newly created video element?
class Video extends React.component{
renderPeers = () => {
return (<video ref={(video) => {this.video = video}}></video>)
}
render() {
return (
<div>
{this.renderPeers()}
</div>
)
}
}
I'm using an range slider <input> element inside a React component to scrub/seek through an HTML5 <audio> element.
see the shortened code of the component:
class Player extends Component {
componentDidMount() {
if(this.player) {
this.player.addEventListener("timeupdate", e => {
this.props.update_time(e.target.currentTime)
this.props.set_duration(e.target.duration)
this.timeBar.value = e.target.currentTime
});
this.timeBar.addEventListener("change", e => {
console.log(this.player)
this.player.currentTime(e.target.value)
})
}
}
render() {
return (
<div className="player">
<input
type="range"
id="seek"
defaultValue={this.props.time}
max={this.props.duration}
ref={ref => this.timeBar = ref}
/>
<audio ref={ref => this.player = ref} >
<source
src={this.props.url}
type="audio/mpeg"
/>
</audio>
</div>
)
}
}
If I move the slider (thus triggering the "change" event), I get the following error:
TypeError: this.player.currentTime is not a function
However, if I try to set the currentTime value directly in the console on the object that is returned by console.log(this.player) it works perfectly fine.
I tried pretty much everything and ran out ouf ideas. The file is fully loaded, the server supports streaming, the this.player object is returned correctly, even inside the event listener.
Thanks for your help!
My particular use case of React is thus:
I wish to add a small React Component to a card that is an existing, fully-functional HTML element, per all the cards on the page. This React Component shall serve to implement a new feature on those cards : reverting changes.
The HTML (well, the MVCE version of it)
is something like this:
<div id="some-id" class="card float-sm-left menu-visual-card " onclick="(function(event) { console.log('I got clicked, and a modal will spawn' ) })(event)">
<div class=card-block>
<h5 class="card-title format-text">Some title</h5>
<!-- some business elements here -->
</div>
<!-- card footer -->
<div class=customized-indicator-react></div>
</div>
The React Component
in its tl;dr version is the following:
class CustomizedIndicatorComponent extends React.Component {
constructor(props) {
super(props)
// business logic
let active = this.props.active
this.state = {
active : active
}
}
toggleActive = () => {
this.setState({
...this.state,
active : !this.state.active
})
}
// setup
componentDidMount() {
// here's where I tried to add a jQuery onclick listener to stop propagation, only to have the React Component listener get stopped
}
// teardown
componentWillUnmount() {
console.log("CustomizedIndicatorComponent destroyed!")
}
// the UI logic
render() {
if (this.state.active) {
return (
<div>
<div
className="badge badge-sm badge-info float-sm-left customized"
style={{marginRight:"10px"}}
>Customized</div>
<div
onClick={(e) => {
e.stopPropagation()
this.toggleActive()
}}
title="Click to undo customizations">
<i className="fa fa-undo" aria-hidden="true"></i>
</div>
</div>
)
}
return <div />
}
}
What happens when you run this?
When I run this, it renders. However, when I click the widget to "de-activate" the element, the container's event-handler still fires!!
I know there is a slew of internet questions about this issue or something close to it, but none of the ones I could find seem to be about this exact use case.
Also, adding an event listener in componentDidMount doesn't work, as that prevents anything from firing!
Is there any way I can make this work without wasting developer-hours refactoring everything including the parent HTMLElements?
A "hacky" way you may consider is to get the parent's id from inside the React component and disable the click event from there.
If id could not be passed as a property to the React component, you can try using ReactDOM.findDOMNode(this).parentNode.getAttribute("id") to get it and then disable the event using:
document.getElementById(id).style.pointerEvents = 'none';
I'm new to react and have to make a project for my bootcamp with it and I am having trouble getting every movie component I render to have an individual button. Every time I click one button, the rest of the buttons on the page act like they are also clicked. Here is my movie component that is being called on.
Heres my first row of components and the buttons are the green ones on the bottom left corner. https://files.slack.com/files-pri/T571CRHGE-F826BKX7S/api.png.
importReact, { Component} from"react";
importAPIfrom"../utils/API"
classMovieextendsComponent{
constructor(){
super();
this.state={
color:'green',
icon:'add',
result:[]
};
}
componentDidMount() {
this.topMovies();
}
topMovies=() =>{
API.topMovies()
.then(res=>this.setState({ result:res.data.results}))
.catch(err=>console.log(err));
}
handleClick=event=>{
if(this.state.color==='green'){
this.setState({color:'red'});
} else{
this.setState({color:'green'});
}
if(this.state.icon==='add') {
this.setState({icon:'remove'});
} else{
this.setState({icon:'add'});
}
}
render() {
constimgURL="https://image.tmdb.org/t/p/w300/"
return(
<div>
{
this.state.result.map((movieList) =>(
<div className="col s4 movieBox">
<div className="card">
<div className="card-image">
<img src={imgURL +movieList.poster_path} />
<span className="card-title"><a id={this.state.color} onClick={this.handleClick} className="btn-floating btn waves-effect waves-light"><i className="material-icons">{this.state.icon}</i></a></span>
</div>
<div className="card-content movieInfo">
<p>Title:{movieList.title}</p>
<p>Genre:{movieList.genre_ids}</p>
<p>Rating:{movieList.vote_average}</p>
</div>
</div>
</div>
))
}
</div>
)
}
}
exportdefaultMovie;
You need to bind the handleClick function ( in fact all functions ) inside the constructor:
constructor(){
super();
this.state={
color:'green',
icon:'add',
result:[]
};
this.handleClick = this.handleClick.bind(this);
}
onClick={()=> this.handleClick()} will also work.
.map() calls a provided callback for each element in your array. So this means that you are creating several buttons that will execute the same event on each of your elements. I suggest creating a row component that handles your onClickEvent and then you could pass the component an id or use an in line arrow function () => this.handleClick(). (this does create a anonymous function on each click and could potentially be bad for performance in larger apps but could work in your case if you don't want to create a row component)
Also you should read up on why using keys with unique ids is important.
https://coderwall.com/p/jdybeq/the-importance-of-component-keys-in-react-js
Hope that helps.
var mark = null;
class Demo extends React.Component {
handleClick(evt) {
mark = "outer";
}
handleSpanClick(evt) {
mark = "inner";
}
render() {
return (
<div onClick={this.handleClick.bind(this)}>
<span onClick={this.handleSpanClick.bind(this)}>
inner
</span>
</div>
)
}
}
For example, I expect that the mark will be "inner" when I click span, but actually, the mark will be "outer". I know the onClick event of span will be called firstly, so I cant get "inner".
How can I get "inner" in this sample?
Example for Bubbling and Capturing in React.js
Bubbling and capturing are both supported by React in the same way as
described by the DOM spec, except for how you go about attaching
handlers.
<div onClickCapture={this.handleClick.bind(this)}>
...