I'm building a React app with material-ui. I want to disable all my radio buttons in a RadioGroup when a certain event happens and re-enable them when the event goes away. (Say when I click a button, all radios are disabled, when I click the same button again, all radios are re-enabled.) I had the following conditional rendering snippet with a ternary operator which does the job but it looks really redundant. Is there a better way to do this? aka. Is there a way to make the prop (disable here) of a Material-ui component into a variable? Thanks!
const radioDisabled = false;
// Some mechanism here that could potentially
// change the value of radioDisabled
{ radioDisabled
?
<RadioGroup row
value={value}
onChange={(e)=>{setValue(e.target.value)}}
>
<FormControlLabel
value='1'
checked={value === '1'}
control={<Radio/>}
label='1'
/>
<FormControlLabel
value='2'
checked={value === '2'}
control={<Radio/>}
label='2'
/>
...
<FormControlLabel
value='n'
checked={value === 'n'}
control={<Radio/>}
label='n'
/>
</RadioGroup>
:
<RadioGroup row
value={value}
onChange={(e)=>{setValue(e.target.value)}}
>
<FormControlLabel
disabled // the only difference from above
value='1'
checked={value === '1'}
control={<Radio/>}
label='1'
/>
<FormControlLabel
disabled // the only difference from above
value='2'
checked={value === '2'}
control={<Radio/>}
label='2'
/>
...
<FormControlLabel
disabled // the only difference from above
value='n'
checked={value === 'n'}
control={<Radio/>}
label='n'
/>
</RadioGroup>
Here are my 2 options to get rid of the redundancy:
1st option is you can opt to remove the ternary conditional rendering and instead render the disabled prop based on a condition e.g. disabled={radioDisabled}
const [radioDisabled, setRadioDisabled] = React.useState(false);
<FormControlLabel
disabled={radioDisabled}
value="1"
checked={value === "1"}
control={<Radio />}
label="1"
/>
2nd option is you can iterate through the values/label of your radio input then assess if you need to disable or not, again, based on a condition
const [radioDisabled, setRadioDisabled] = React.useState(false);
const radioInputs = [
{
value: 1,
label: 1
},
{
value: 2,
label: 2
},
{
value: 3,
label: 3
}
];
{radioInputs.map((radioInput) => {
return (
<FormControlLabel
disabled={radioDisabled}
value={radioInput.value}
checked={value == radioInput.value}
control={<Radio />}
label={radioInput.label}
/>
);
})}
CodeSandBox: https://codesandbox.io/s/patient-worker-8mrq3?file=/src/App.js:1717-2041
import { useState } from 'react'
const [isRadioDisabled, setIsRadioDisabled] = useState(false)
<Button title='Disables RadioButtons'
onPress={() => setIsRadioDisabled(prevState => !prevState)} />
<RadioGroup row
value={value}
onChange={(e)=>{setValue(e.target.value)}}
>
<FormControlLabel
disabled={radioDisabled}
value='1'
checked={value === '1'}
control={<Radio/>}
label='1'
/>
<FormControlLabel
disabled={radioDisabled}
value='2'
checked={value === '2'}
control={<Radio/>}
label='2'
/>
<FormControlLabel
disabled={radioDisabled}
value='n'
checked={value === 'n'}
control={<Radio/>}
label='n'
/>
</RadioGroup>
Use React's useState hook to toggle between states to disable and enable FormControlLabels. Instead of using a variable or prop. Then, use a button to toggle between the true and false of the created state as shown above. There's no need to conditionally render them, since the disabled prop accepts a boolean to toggle from false to true.
Related
I am trying to get radio mui radio button for testing but it fails. I used getByTestId, getByLabelText, queryByLabelText.
describe("Radio group test cases", ()=>{
test("Radio group change value and new value updated and last value no more checked", () => {
render();
// Before change selection
const radionButtonMale = screen.getByTestId('Male') as HTMLInputElement;
//expect(radionButtonMale).toHaveProperty("checked", true);
expect(radionButtonMale.checked).toEqual(true);
// Change selection
const radionButtonFemale = screen.getByTestId('Female') as HTMLInputElement;
fireEvent.click(radionButtonFemale, { target: { checked: true }});
expect(radionButtonFemale.checked).toEqual(true);
// Old value is no more checked
expect(radionButtonMale.checked).toEqual(false);
});
})
Index.ts
<>
<FormControl fullWidth>
<FormLabel id="buttons-group-label">{placeholder}</FormLabel>
<RadioGroup
aria-labelledby="buttons-group-label"
value={!value ? defaultValue : value}
// onChange={onChange}
// label={placeholder}
name="radio-buttons-group"
{...otherprops}
>
{fieldConfig?.options?.map((option) => (
<FormControlLabel key={option.displayValue} value={option.displayValue} control={<Radio inputProps={{
// #ts-ignore
'data-testid': `${option.displayValue}`,
}} />} label={option.displayValue} />
))}
</RadioGroup>
</FormControl>
{!valid && touched && <ErrorMessage>{errorMessage}</ErrorMessage>}
</>
It Looks like material creating the nested radio button dom so I am unable to get the radio button.
Error:
Trying to make a program where there are radio switches each equating to a different boolean value. Depending on the boolean value, it would either make the 'disable' prop on the textfield either true or false. My code allows for the button to be default selected as enabled editing and when I select disable it disables the textfield. However, if I click disable then try and click enable again it won't change the textfield from disable.
const [radioEdit, setRadioEdit] = React.useState(false);
<RadioGroup
value={radioEdit}
onChange={(e) => setRadioEdit(e.target.value)}
aria-labelledby="demo-radio-buttons-group-label"
name="radio-buttons-group"
row
>
<FormControlLabel
value={true}
control={<Radio />}
label="Disabled"
/>
<FormControlLabel
value={false}
control={<Radio />}
label="Enabled"
/>
<p>{String(radioEdit)}</p>
<TextField
id="outlined-basic"
variant="outlined"
size="small"
////////RIGHT HERE////////
value={data["companyname"]}
disabled={radioEdit}
/>
If the default state of radioEdit isn't 'false', it is automatically disabled (set to true or null) and won't let me update it multiple times.
The issue is with onChange you have defined with RadioGroup. Usually, we define
onChange={(e) => setRadioEdit(e.target.value)}
to set the value of text input onEventChangeHandler. But here it's for the Radio button. I was using typescript to find the answer for this and as soon as I copy-pasted your code it showed me the error at setRadioEdit(e.target.value) whereas the setRadioEdit should be boolean. The reason why TypeScript is super useful.
The answer is
onChange={() => setRadioEdit(!radioEdit)}
I'm toggling my state here onChange. So when we setRadioEdit as true, it's actually the radioEdit would be set as true. That's how the useState hook works. So by defining setRadioEdit(!radioEdit) we are toggling the state. If it's true it changes to false and vice versa.
Also you will have to close the </RadioGroup> component. Complete answer
const [radioEdit, setRadioEdit] = useState(false);
return (
<>
<RadioGroup
value={radioEdit}
onChange={(e) => setRadioEdit(!radioEdit)}
aria-labelledby="demo-radio-buttons-group-label"
name="radio-buttons-group"
row
>
<FormControlLabel value={true} control={<Radio />} label="Disabled" />
<FormControlLabel value={false} control={<Radio />} label="Enabled" />
</RadioGroup>
<p>{String(radioEdit)}</p>
<TextField
id="outlined-basic"
variant="outlined"
size="small"
disabled={radioEdit}
/>
</>
);
I am trying to disable a checkbox group based on the value of a radio group. I followed the method used in the last part of the Formik tutorial. Using react context removes a lot of clutter from the form itself but I'm not sure how to expose some values now.
In the form below, in the CheckboxGroup component, I'm attempting to print the word disabled as an attribute of checkbox1 if radio4's value is "yes". I'm not sure what value should be used here as fields doesn't work. How do I pass a value to the form given the React Context method used?
The form:
export default function HealthAssessmentForm() {
return (
<Formik
initialValues={{
radio4: '',
symptoms: '',
}}
onSubmit={async (values) => {
await new Promise((r) => setTimeout(r, 500));
console.log(JSON.stringify(values, null, 2));
}}
validator={() => ({})}
>
<Form>
<RadioInputGroup
label="Disable the checkbox?"
name="radio4"
options={['Yes','No']}
/>
<CheckboxGroup
{(fields.radio4.value === "yes") ? "disabled" : null}
name="checkbox1"
options={[
{name:"hello",label:"hello"},
{name:"there",label:"there"},
]}
/>
<button type="submit">Submit</button>
</Form>
</Formik>
)
}
I'm not sure the custom components are relevant here but...
const RadioInputGroup = (props) => {
const [field, meta] = useField({...props, type:'radio'});
return (
<FormControl component="fieldset">
<FormLabel component="legend">{props.label}</FormLabel>
<RadioGroup aria-label={props.name} name={props.name} value={props.value}>
<FieldArray name="options">
{({ insert, remove, push }) => (
props.options.length > 0 && props.options.map((option,index) => (
<FormControlLabel key={index} {...props} value={option.toLowerCase()} control={<Radio />} label={option} />
))
)}
</FieldArray>
</RadioGroup>
</FormControl>
)
};
const CheckboxGroup = (props) => {
const [field, meta] = useField({...props, type: 'checkbox', });
return (
<FormControl component="fieldset">
<FormLabel component="legend">{props.label}</FormLabel>
<FormGroup>
<FieldArray name="options">
{({ insert, remove, push}) => (
props.options.length > 0 && props.options.map((option,index) => (
<FormControlLabel
{...field} {...props}
key={index}
control={<Checkbox />}
label={option.label}
/>
))
)}
</FieldArray>
</FormGroup>
<FormHelperText>Be careful</FormHelperText>
</FormControl>
)
}
I wrapped the whole <Form> in a function that passes props as an argument. I then get access to props.values.radio1. However, that has exposed that radio1 does not have a value even when it is clicked, which should be a separate issue.
{(props) => (
<Form>
<RadioInputGroup
label="Disable the checkbox?"
name="radio4"
options={['Yes','No']}
/>
<CheckboxGroup
disabled={props.values.radio1 === "No"}
name="checkbox1"
options={[
{name:"hello",label:"hello"},
{name:"there",label:"there"},
]}
/> </Form>
)}
So I am stuck with This I have two objects :
options = {'Not Ok':'Not Ok', 'Watch':'Watch', 'Ok':'Ok'};
choice_colors = {'Ok':'green', 'Not Ok':'red', 'Watch':'yellow'};
I am using a map function to generate radio buttons with reference to material UI
let choices = _map(options, function(choice, key){
return <FormControlLabel key={key}
id={key}
value={key+''}
control={<Radio />}
label=""
/>;
I am getting desired output 3 radio buttons from control={<Radio />}
But now I want to set the color for each of them according to their key values like :
first radio button have key 'ok then its color should be "green" in reference from
choice_colors = {'Ok':'green', 'Not Ok':"red", 'Watch':'yellow'};
I tried
control={<Radio style={{color:'red'}} />}
above passing red to all three radios
control={<Radio style={{color:`${key==="Ok" ? red : ' '}`}} />}
above not giving desired out put cause I am not able to add multiple check
Thanks in advance !!
You can use the choice_colors dictionary in your Radio style property like so:
const options = {'Not Ok':'Not Ok', 'Watch':'Watch', 'Ok':'Ok'};
const choice_colors = {'Ok':'green', 'Not Ok':'red', 'Watch':'yellow'};
let choices = _map(options, function(choice, key) {
return (
<FormControlLabel key={key}
id={key}
value={key+''}
control={<Radio style={{ color: choice_colors[key] }} />}
label=""
/>
);
});
I am new to ReactJS. Please forgive me if it is so simple.
I am trying to inject the radio button component (RadioButton.js) into home page. So that the radio button appear on home page. It like a child. As you can see from RadioButton.js, I have two radio buttons. Their values are buttonOne and buttonTwo.
What I am trying to achieve is that when buttonOne is selected, I would like to show <TablePage/> components. otherwise, <StickyHeadTable />
RadioButton.js
export default function FormControlLabelPosition() {
const [value, setValue] = React.useState("female");
const handleChange = event => {
setValue(event.target.value);
};
return (
<FormControl component="fieldset">
<RadioGroup
aria-label="position"
name="position"
value={value}
onChange={handleChange}
row
>
<FormControlLabel
value="buttonOne"
control={<Radio color="primary" />}
label="F1"
/>
<FormControlLabel
value="buttonTwo"
control={<Radio color="primary" />}
label="F2"
/>
</RadioGroup>
</FormControl>
);
}
RadioButton is injected in homepage. How can i get the values from RadioButton.js. So that I can use the condition.
HomePage.js
return (
<div className="home-page">
<RadioButton values={values} handleChange={handleChange}></RadioButton>
{values.flight === "buttonOne" ? <TablePage /> : <StickyHeadTable />}
</div>
);
RadioButton.js
export default function FormControlLabelPosition(props) {
return (
<FormControl component="fieldset">
<RadioGroup
aria-label="position"
name="position"
value={props.value}
onChange={props.handleChange}
row
>
<FormControlLabel
value="buttonOne"
control={<Radio color="primary" />}
label="F1"
/>
<FormControlLabel
value="buttonTwo"
control={<Radio color="primary" />}
label="F2"
/>
</RadioGroup>
</FormControl>
);
}
HomePage.js
const [value, setValue] = React.useState("female");
const handleChange = event => {
setValue(event.target.value);
};
return (
<div className="home-page">
<RadioButton values={values} handleChange={handleChange}></RadioButton>
{values.flight === "buttonOne" ? <TablePage /> : <StickyHeadTable />}
</div>
);
If you want to use the value from the RadioButton component, you should create it as an uncontrolled form component meaning that its value would come from it's parent, in this case the HomePage component.
So the RadioButton.js would be:
export default function RadioButton({ value, onChange }) {
return (
<FormControl component="fieldset">
<RadioGroup
aria-label="position"
name="position"
value={value}
onChange={onChange}
row
>
<FormControlLabel
value="buttonOne"
control={<Radio color="primary" />}
label="F1"
/>
<FormControlLabel
value="buttonTwo"
control={<Radio color="primary" />}
label="F2"
/>
</RadioGroup>
</FormControl>
);
}
RadioButton.propTypes = {
value: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired
};
And the HomePage.js
export default function HomePage() {
const [value, setValue] = React.useState("buttonOne");
const handleChange = event => {
setValue(event.target.value);
};
return (
<div className="home-page">
<RadioButton value={value} onChange={handleChange}></RadioButton>
{value === "buttonOne" ? <TablePage /> : <StickyHeadTable />}
</div>
);
}
On the HomePage.js you can use state for showing up the table conditionally based on radio button value.
I assume RadioButton.js component is called in HomePage.js as component.
RadioButton.js
export default function FormControlLabelPosition(props) {
const [value, setValue] = React.useState("female");
const handleChange = event => {
setValue(event.target.value);
> //Send your radio button value to parent component i.e HomePage.js
props.handleChange(event.target.value);
};
return (
<FormControl component="fieldset">
<RadioGroup
aria-label="position"
name="position"
value={value}
onChange={handleChange}
row
>
<FormControlLabel
value="buttonOne"
control={<Radio color="primary" />}
label="F1"
/>
<FormControlLabel
value="buttonTwo"
control={<Radio color="primary" />}
label="F2"
/>
</RadioGroup>
</FormControl>
);
}
HomePage.js
state = {
radioButtonValue: '';
}
render () {
return (
<div className="home-page">
<RadioButton handleChange={this.handleChange} />
{this.state.radioButtonValue === "buttonOne" ?
<TablePage /> : <StickyHeadTable />}
</div>
);
}
handleChange = (radioButtonValue) => {
this.setState({radioButtonValue});
}
One the above code, we are sending handleChange as a props and change the state as soon as radio-button is clicked and then rendering the table based on the state.