I would expect that setting the disabled attribute on a react component would block the onClick handler for that element.
<a role="button"
className={`btn btn-block btn-info`}
disabled={!this.state.readyToView}
href={this.state.selectedObjectLink}
onClick={this.handleLink}
>View</a>
but although the element shows a "disabled" attribute it still registers a click event.
Edit: I should clarify - I handle the click event in handleLink, I want to know why the disabled attribute doesn't remove the handler? Sorry for any confusion.
The problem isn't with disabled; it's with the HTML element a. Anchor <a> cannot have a disabled property (what does that even mean?). Just because you've passed CSS to make the element look like a button, doesn't make it a button. It is still an anchor.
The solution would be either to use something else (like button):
<button
role="button"
className={`btn btn-block btn-info`}
disabled={!this.state.readyToView}
onClick={this.handleLink}
>
View
</button>
You can use this.state.selectedObjectLink inside handleLink if you want to redirect to a page
Or use one of the many other suggestions on this page.
Why not just handle this in handleLink?
handleLink () {
if (!this.state.readyToView) return
// ...
}
If you really want to bind/remove the handler dynamically, you can do something like this:
const clickHandler = this.state.readyToView ? this.handleLink : null
...
<a role="button"
...
...
onClick={clickHandler}
>View</a>
You can add a condition in your click handler, something like this
<a role="button"
className={`btn btn-block btn-info`}
disabled={!this.state.readyToView}
onClick={this.state.readyToView && this.handleLink}
>
View
</a>
jsfiddle
If you are using react version 16 and up
on onClick don't call the method directly use () => method instead like this
const handleRemoveBtnClick = () => {
...
}
<button ...onClick={() => handleRemoveBtnClick} />
Another trick to disable the click to any components is to use useState with boolean value either true to disable or false to resume the click functionality
example
export default const ElementComponent() =>{
//set the initial value of disable click to false
const [disableClick,setDisableClick] = useState(false)
const anotherFunction =() =>{
console.log("I've been run")
}
const handleClick()=>{
//if disableClick is false then run this if block, else don't do anything
if(!disableClick){
anotherFunction()
}
}
return(
<img src="..." onClick={handleClick}/>
)
}
the good thing about this is that we can pass the function as a props to another components and we can run it there, we can even let's say disable a click for let's say 1 second using setTimeout function, there are tons of way you can use this method, hope it helps anyone if you want to use onClick not only on the button element itself
Related
I have a svelte app where
licking a button "Show" sets a show variable to true which shows a input text box and a save button.
Clicking the "Save" button calls a function which sets the show variable to false
Testing shows that clicking Show also triggers the on:click of Save.
Google tells me to add stopPropagation to fix this issue, but it does not fix this issue.
Any hints on what is my mistake?
A repl with my code is available at
https://svelte.dev/repl/592a544ac59a45b385ab153dec7a42f1?version=3.55.1
I forked the repl and made some changes to it
https://svelte.dev/repl/b897aa42e87d4adc8c04b381b5a66692?version=3.55.1
Here is the new code:
<script>
var name = ''
let names=[];
let show=false;
function addName(){
console.log("Clicked");
show=false;
if (name.length > 0){
names.push(name);
console.log(names)
}
}
</script>
<button on:click={()=>(show=true)} > Show
</button>
{#if show}
<input bind:value={name} type="text">
<button on:click={()=> {addName()}}>Save</button>
{/if}
<h1>Hello {name}!</h1>
You shouldn't have a propogation issue because the event listeners are not nested elements https://www.tutorialrepublic.com/javascript-tutorial/javascript-event-propagation.php
Your Save button on:click was setup like
<button on:click={addName()}>Save</button>
This definition is not correct because on:click={addName()} calls the addName function immediately. If you use this syntax you likely need to write it like this
on:click={addName}
Otherwise you can write it like your other on:click with an anonymous function (which is what I did).
on:click={()=> {addName()}}
I'll try to explain this further.
I have a material-UI List component, with ListItem component that is set to button=true thus makes the whole item a button.
inside I added that inside him I have a FontAwesomeIcon.
To hide the button I put it's style to visibility: "hidden" and the Icon to visibility: "visible" so it would be available to see. (little bad practice maybe, but did not though of another way).
Now, when someone presses the ListItem anywhere without the Icon, it activates the onClick of that ListItem - as it should, and it's good! but, when pressing the area where the Icon is, both OnClick events of the "Icon button" and the ListItem is called - as it should, but I don't want it to be that way.
Now, is there a way to make the small "nested" button to be "on top" of the parent button so only it's event would be called?
If not, is there a way to know from the parent onClick that it's pressed on the area without the Icon so I would call different functions based on the click area?
Also, any other idea will be gladly received as I am new to react and web in general and I'd want to have the best practices solutions.
Many thanks :)
This is unrelated to React. In JavaScript you can use event.stopPropagation() method to stop the propogation of event at any level.
https://www.w3schools.com/JSREF/event_stoppropagation.asp#:~:text=Definition%20and%20Usage,capturing%20down%20to%20child%20elements.
Here is the example of how you would do it in React
import React from "react";
import "./styles.css";
export default function App() {
const parentButtonHandler = () => {
console.log("parent");
};
const childButtonHandler = (e) => {
console.log("child");
e.stopPropagation();
};
return (
<div className="App">
<button onClick={parentButtonHandler}>
Hello CodeSandbox
<button onClick={childButtonHandler}>
Start editing to see some magic happen!
</button>
</button>
</div>
);
}
If I understand your question correctly, you got that issue because the event is bubbled.
You can read this for more information: https://javascript.info/bubbling-and-capturing
To solve it, you can use event.stopPropagation() in the event handler for click event on "Icon button", so the event wont be bubbled to the parent element which is the ListItem
I think it's bad idea to make nested buttons. it's harder to support and it makes your layout messy.
In your case you can do it based on few ideas:
You have two separate buttons in your ListItem
export const Comp = () => {
return (
<ListItem>
<button onClick={handleOnMainClick}>mainButton</button>
<button onClick={handleOnSecondClick}>secondButton</button>
</ListItem>
)
}
But it works if your buttons on left side or right side only.
If you want to place your functional button whatether you want you can place it by position
export const Comp = () => {
return (
<ListItem styles={{position: 'relative'}}>
<button onClick={handleOnMainClick}>mainButton</button>
<button
styles={{position: 'absolute', top: '50%', left: '50%'}}
onClick={handleOnSecondClick}>
secondButton
</button>
</ListItem>
)
}
The onClick attribute for a button element created within a variable is not firing.
I tried directly defining the function in the onClick attribute, and simply out-putting to the console, but there is still nothing output to the console, and the button is not working as expected.
I also added a 'disabled={false}' attribute to the button to make sure that was not an issue, but the onClick attribute is still not working as expected.
let display = (<div className ='dtaskhome'>
<h1>Tasks</h1>
<button disabled={false} onClick={newTask} className='btask'>New Task +</button>
<ul className ='ultasks'>{taskItems}</ul>
</div>);
function newTask() {
console.log('point reached');
Tasks.props.state.newTask = true;
}
No error messages related to the onClick attribute are being displayed, and the current code correctly renders the component.
I also added a 'disabled={false}' attribute to the button to make sure
that was not an issue, but the onClick attribute is still not
responsive.
Try implementing the function as a method.
newTaskHandler = (props) => {
console.log('point reached');
props.state.newTask = true;
}
Then try
onClick={this.newTask(this.props)}
Hope this helps you.
try to call the function:
onClick={newTask()}
And if not try to call it with this.
onClick={this.newTask()}
I have a React project where a component SubmitButton is rendered when the property isSelectedNumber change its state to true. The component SubmitButton, which is a button you can click, will call a method when the button is clicked by using the onClick function and that will lead to the property isSubmitClicked change to true that the component NextButton will render.
The thing is that just the SubmitButton is rendered and when I click the button of the component SubmitButton it doesn't render the component NextButton.
This the part of the wrapper component where both components will be rendered if the conditions are true.
{this.state.isSelectedNumber ? <SubmitButton handleClickSumbmit={this.handleClickSumbmit}/> : null}
{this.state.isSubmitClicked ? <NextButton /> : null}
This is the part of the SubmitButton Component where the onClick function should call the handleCliclkSubmit method to change the property state:
<button type="button" onClick={this.props.handleClickSubmit}></button>
This is the handleClickSubmit method:
handleClickSumbmit () {
this.setState({
isSubmitClicked: true
});
}
I was wondering if you have any idea what could be happening and how to solve it.
You have typo error
Change
<button type="button" onClick={this.props.handleClickSubmit}></button>
To
<button type="button" onClick={this.props.handleClickSumbmit}></button>
Also the function name is not meaningful in your code. Change handleClickSumbmit to handleClickSubmit wherever you have handleClickSumbmit
Also since you are using regular function you have to bind it in constructor. I hope you already did that.
I think that you should check the calling of handleClickSubmit, where you call it as handleClickSumbmit, maybe that's where the problem lies.
I'm trying use React events to access a custom 'value' assigned to a button, but I get different results depending on where I click on the button. I can probably use getDOMNode() or this.state to get the desired result but I'm little confused on how to use 'React Events' and it's behavior.
Is it best to use synthetic events on a single element like <input>? Is there a way to get the value of a button using react events?
Note: I'm using bootstrap glyphicon inside the <button> element.
var Content = React.createClass({
handleClick: function(e) {
console.log( e.target );
},
render: function() {
return (
<div>
<button type="button" value="button1" className="btn btn-default" onClick={this.handleClick}><span className="glyphicon glyphicon-ok"></span> Submit</button>
</div>
)
}
});
Jsfiddle
console.log( e.target ) results:
Move the mouse over the glyphicon 'check mark', and click.
<span class="glyphicon glyphicon-ok" data-reactid=".0.0.0"></span>
Move the mouse over the word 'Submit' and click
<span data-reactid=".0.0.1"> Submit</span>
Move the mouse anywhere else inside the button, and click
<button type="button" value="button1" class="btn btn-default" data-reactid=".0.0"><span class="glyphicon glyphicon-ok" data-reactid=".0.0.0"></span><span data-reactid=".0.0.1"> Submit</span></button>
I'm new to synthetic events and DOM behaviors as you guys can tell. Any guidance would be greatly appreciated! Thanks.
I think you want e.currentTarget.getAttribute('value')
Using currentTarget will get the button since the event will bubble up to the button. You are getting the span element since you're likely clicking the span. That's what the value of target is.
Also here is the updated fiddle: http://jsfiddle.net/v27bqL5y/1/
Another way to do this is to use refs. If you want to stay away from using stuff like e.currentTarget, this can be a simpler way to go.
See the fiddle: http://jsfiddle.net/v27bqL5y/2/