When a button (material ui) is clicked for a second time, I want that button to be disabled (disabled={true}). I did not find any example related to this on StackOverflow.
<Button
onClick={this.startDraw.bind(this)}
disabled={}
startIcon={<Brush />}
>
At first, the button is clickable. When it is clicked, something happens, but when this same button is clicked a second time, the button should be disabled (cannot be clicked anymore).
For Class component use
state = {
count: 0
};
this.setState({ count: count + 1 }); // use this on your button click
and for the button part
<Button
onClick={this.startDraw.bind(this)}
disabled={state.count == 2}
startIcon={<Brush />}
/>
for functional component use this approach
const [count , setCount ] = useState(0);
setCount(count + 1) // use this on your button call
<Button
onClick={this.startDraw.bind(this)}
disabled={count == 2}
startIcon={<Brush />}
/>
Related
Having a hard time seeing how I could accomplish this. I created some custom number buttons from 0-9 that users can click on instead of using the keyboard. The problem I'm having is I have multiple dynamically created input fields depending on JSON Data so let's say there are 10 dynamically created input fields and a user starts with question one and the user then uses the custom number buttons I created and clicks numbers "145" to answer question one, but what happens is then all 10 inputs have the same number "145" not the problem the user was trying to solve. I'm using the context API to then save the values typed in on a function called getButtonValue that I then call to the parent component and save the values in a state array, so I know that my problem is that all the inputs share the same state array but how could I make sure the correct input the user clicks on is only receiving those values.
Thanks in advance.
My Custom Number Button Component:
import { FormContext } from "../../lib/FormContext";
function ActivityBar() {
const { getButtonValue } = useContext(FormContext);
return (
<div className={`${activity.activity__workSheet__numberButton}`}>
<button value={0} onFocus={(e) => getButtonValue(e)}>
<img
className={`${activity.activity__workSheet__img0}`}
src={"/assets/activityNumber-btn.png"}
alt="activity number button"
/>
.... more code
Parent Component:
const [numberButtonClicked, setNumberButtonClicked] = useState([]);
const getButtonValue = (e) => {
setNumberButtonClicked((prevButtonClicked) => [
...prevButtonClicked,
e?.target?.attributes[0].value
]);
};
return (
<Carousel>
<div ref={imageRef} style={{ height: "100%" }}>
{Object.entries(elements).map((element, i) => {
const { fields } = element[1];
if (fields) {
return (
<Element
key={i}
field={fields[0]}
id={i}
useReff={`answer${i}`}
currentValue={
numberButtonClicked === "" ? null : numberButtonClicked.join("")
}
/>
);
} else {
return;
}
})}
</div>
</Carousel>
Got a good working version figured out for this scenario, what I did was.
I have a onFocus method on my input tags that then takes in the event and calls a handleChange(e) function. Within that function I then save the currentInputId in a variable by using e?.target?.attributes[0]?.value and the previous InputId in a state variable and just check if the previous InputId is equal to the currentId user just focused on. If so then we'll add the next number user clicks into the same field, else if previousInputId !== currentInputId then make my user value state array empty, setNumberButtonClicked([]).
<section key={i}>
<input
type='radio'
key={attribute.name + item.id}
id={attribute.name + item.id}
name={attribute.name}
value={item.value}
defaultChecked={i === 0}
onClick={(event) => inputClick(attribute, event)}
/>
<label
htmlFor={attribute.name + item.id}
>
{
item.value
}
</label>
</section>
The code above is more or less what a .map() function is supposed to return in my React.js APP, creating input radio buttons for customizing a product before adding it to the cart state. All I did was remove some classes, etc. that were there for CSS purposes, etc.
Ideally, what is supposed to happen here is that...
When rendering the product page for the first time, the very first input radio button that is returned by .map() should be checked by default. This works thanks to the "defaultChecked" attribute. No problems here.
After I click a different input radio button (not the "defaultChecked" one), the checked input should change and all the other inputs should be left unchecked. As I understand it, input radio buttons with the same 'name' attribute do this automatically.
When clicking the input radio button, the "onClick" function should trigger. This is where the code is not functioning as I wish it would.
The issue is that when my page renders for the first time and I click on an input radio button (other than the "defaultChecked") the "onClick" function does not trigger. It only triggers when I have clicked on a different input once and then on another.
A.k.a. it triggers on the second click. After that second click, it works as intended - every time a different input radio button is selected/clicked on - the function triggers, but not for the very first time.
I tested this with console.log("I am triggered") at the end of the "onClick" "inputClick(attribute, event)" function, and only on the second click would the console log "I am triggered".
I was able to fix the issue by removing the "defaultChecked" attribute. I think the issue might be tied to the fact that the "onClick" function is only able to be triggered when one input gains the "checked" attribute and another loses it, but the "defaultChecked" attribute does not count as an input being "fully checked" or something like that.
I could leave it at that, but the project that I am working on required me to have a default checked input radio button on the first-page render. So, I can't just delete the "defaultChecked" attribute and call it a day.
Any ideas on what could be causing this behavior?
UPDATE1
The following is the body of the inputclick() function:
//* Handle input selection
const inputClick = (attribute, event) => {
//* Parse state
let state = JSON.parse(JSON.stringify(itemState));
//* Get all the required values from the clicked input
const attributeId = attribute.id;
const itemTargetValue = event.target.value;
//* Check if the attribute is in state
const attributeIs = state.some(item => item.id === attributeId);
//* If the attribute does not exsist - add the attribute to state
if(attributeIs === false) {
const obj = {
id: attributeId,
selectedItem: itemTargetValue
};
state.push(obj);
return setitemState(state);
}
//* If the attribute id already exsists in state
if(attributeIs) {
//* Find the index of the attribute in question
const attributeIndex = state.map(object => object.id).indexOf(attributeId);
const attributeInQuestion = state[attributeIndex].selectedItem;
//* If the attribute's item's id is the same as the seelected input - do nothing
if(attributeInQuestion === itemTargetValue) {
return
}
//* If the attribute's item's id is not the same - change it to the new value
if(attributeInQuestion !== itemTargetValue) {
state[attributeIndex].selectedItem = itemTargetValue;
console.log(state);
return setitemState(state);
}
}
};
Here is the working code that fixes the issue.
Yes, there is some streamlining, for example, code shortening, etc. Yet, the difference that solves the issue is that...
The code that I had posted in the question originally was working. Meaning, that it was firing the inputClick() function and changing which input was selected, the problem was that...
...the defaultChecked logic in the was preventing the chosen input from being rendered as a selected input a.k.a. to change its CSS styling.
Bellow is the new onClick() function.
//* Handle input selection
const inputClick = (product, attribute, event) => {
let newCart = JSON.parse(JSON.stringify(cartState));
const productId = product.id;
const attributeId = attribute.id;
const itemTargetValue = event.target.value;
//* Find the product in cart state */
const productIndex = newCart.map((object) => object.id).indexOf(productId);
//* Find the attribute by id in question */
const attributeIndex = newCart[productIndex].selectedAttributes.map(object => object.id).indexOf(attributeId);
//* Change the products selected attribute item */
newCart[productIndex].selectedAttributes[attributeIndex].selectedItem = itemTargetValue;
setcartState(newCart);
};
Below is what the "inside" of the looks like now.
<input
type='radio'
key={product.id + attribute.name + item.id}
id={product.id + attribute.name + item.id}
name={product.id + attribute.name}
value={item.value}
defaultChecked={product.selectedAttributes[selectedId].selectedItem === item.value}
onChange={(event) => inputClick(product, attribute, event)}
>
</input>
`export default function Ratings(props){
const[hover,setHover] =useState(false); // checks for hover state
const [com, setCom] = useState(false); //checks for click state
function isHover(){
setHover(true);} //connects to onMouseOver event then sets the hover state
function isNotHover(){ //connects to onMouseLeave event then sets the hover state
setHover(false);}
function op(){ //Send the Id of the rating button back to app.js so
props.op(props.id);} // it can be then forwarded to another page
function designs(){ //connects the click to sate, if the state is true it makes it false
com ? setCom(false):setCom(true)} // and vice verca
function bth(){ // I have two functions on click so this combines both
op() //the functions and gives it as one to the clicke event
designs()}
pressed //is style after clicked
rateStyle //is style before clicked
return(
<div style={hover|| com ? pressed: rateStyle} onMouseOver={isHover}
onMouseLeave={isNotHover} onClick={bth} >
{props.valN}
</div>)
}`I have five rating buttons and I want to unclick the already clicked button when another one is clicked. By clicking I mean, When I click one of the buttons their style is changed mainly background colour now I want when somebody presses another rating I want the style for the previously clicked button to go back to normal and the newly pressed button to go to active state help.
I used this method for this question.
inside your button
<button id="button" onClick={
(e) => {
if(res === "unpressed"){
//if button is pressed for first
//time
e.target.style.backgroundColor ="rgb(195, 197, 64)";
setRes(pressed);
//Update res into false
}else{
//if button is pressed for second
//time
e.target.style.backgroundColor ="rgb(195, 17, 64)";
setRes(unpressed);
//Update res into false
}
}
}>
STAR
</button>
using Hooks
import { useState } from "react";
const [res,setRes] = useState("unpressed");
I have a checkbox and a button.
When I click the checkbox, count is updated using setCount and incremented by 1.
When I click the button, I want to click the checkbox 10 times.
So, setCount should update count value 10 times and final value of count should be 10.
import { useEffect, useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("count updated to :", count);
}, [count]);
return (
<div className="App">
<button
id="start"
onClick={(e) => {
for (let i = 0; i < 10; i++) {
document.getElementById("check").click();
}
}}
>
start
</button>
<input
id="check"
type="checkbox"
value={count}
onClick={(e) => setCount(count + 1)}
/>
</div>
);
}
But the problem is when I click the button, count only increased by 1. I'm sure its related to asynchronicity of React Hooks.
How to make the checkbox click and update the state properly 10 times?
It's usually not a good idea to access DOM elements directly when using react. I can't see why this might not solve your problem:
<button
id="start"
onClick={(e) => {
setCount(pc=>pc+10)
}}
>
and if you need to see the click event you can always perform some async action that increments the count value over some sort of timeout.
But if you really need to perform a click event on your check box use can use refs.
I have an RMWC Button element, and I want to change the icon attribute when an onClick event is fired.
<Button outlined icon={<CircularProgress />}
onClick={(e)=> {
// e.currentTarget.icon = '';
// console.log(e.currentTarget.icon)
// ??? :V
}}
>Export</Button>
More specifically, I'm trying to make the Button stop loading when the button is clicked :P
You could do with useState update method
const [load,setLoad] = useState(true);
<Button outlined icon={load ? <CircularProgress />:<SomeOtherIcon/>}
onClick={(e)=> setLoad(false)} >Export</Button>