I am trying to use the radio buttons from material-ui - https://material-ui.com/components/radio-buttons/
Although the example here doesn't provide the selected radio button on submitting the form. I am also trying to use redux-forms - https://redux-form.com/6.0.0-rc.4/examples/material-ui/ but their documentation seems out of date. I am not sure how you would pre-select a radio button for example.
renderRadioGroup.js
import React from 'react';
import Radio from '#material-ui/core/Radio';
import RadioGroup from '#material-ui/core/RadioGroup';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import FormControl from '#material-ui/core/FormControl';
import FormLabel from '#material-ui/core/FormLabel';
const renderRadioGroup = ({ input, label, value, fieldName, handleChange, options, meta: { touched, error }}) => (
<FormControl component="fieldset" fullWidth={true}>
<FormLabel component="legend">{label} {value}</FormLabel>
<RadioGroup
row
aria-label={fieldName}
name={fieldName}
value={value}
onChange={handleChange}
>
{
options.map((item, j) =>
<FormControlLabel key={j} value={item.value} disabled={item.disabled} control={<Radio />} label={item.label} />
)
}
</RadioGroup>
</FormControl>
)
export default renderRadioGroup;
shell
<Field
name="paymentplan"
component={renderRadioGroup}
label="Do you wish to pay monthly or annually?"
value={"1"}
fieldName="paymentplan"
options={
[
{
"label" : "Monthly",
"value" : "0"
},
{
"label" : "Annually",
"value" : "1"
}
]
}
/>
Related
I'm using material ui select element with added functionality such as multiple selection with checkbox, my question is, is there a way to delete and update name from select element itself ?
for example: by clicking the pen next to 'Oliver Hansen' i could update that name or by clicking recycle bin delete that name ?
code to try:
https://codesandbox.io/s/material-ui-multiple-select-with-select-all-option-forked-nrm6z4?file=/src/App.js
code:
import React, { useState } from "react";
import Checkbox from "#material-ui/core/Checkbox";
import InputLabel from "#material-ui/core/InputLabel";
import ListItemIcon from "#material-ui/core/ListItemIcon";
import ListItemText from "#material-ui/core/ListItemText";
import MenuItem from "#material-ui/core/MenuItem";
import FormControl from "#material-ui/core/FormControl";
import Select from "#material-ui/core/Select";
import DeleteIcon from "#material-ui/icons/Delete";
import CreateIcon from "#material-ui/icons/Create";
import { MenuProps, useStyles, options } from "./utils";
function App() {
const classes = useStyles();
const [selected, setSelected] = useState([]);
const handleChange = (event) => {
console.log("vals", event.target);
const value = event.target.value;
setSelected(value);
console.log("values", selected);
};
return (
<FormControl className={classes.formControl}>
<InputLabel id="mutiple-select-label">Multiple Select</InputLabel>
<Select
labelId="mutiple-select-label"
multiple
variant="outlined"
value={selected || []}
onChange={handleChange}
renderValue={(selected) => selected}
MenuProps={MenuProps}
>
{options.map((option) => (
<MenuItem key={option.id} value={option}>
<ListItemIcon>
<Checkbox checked={selected?.includes(option)} />
</ListItemIcon>
<ListItemText primary={option.title}>{option}</ListItemText>
<DeleteIcon />
<ListItemIcon>
<CreateIcon />
</ListItemIcon>
</MenuItem>
))}
</Select>
<p>{selected}</p>
</FormControl>
);
}
export default App;
Yes you can, you need to store your options in a state, and on the delete button you can stopPropagation and filter options of clicked option, and the same you can do to the edit.
import React, { useState } from "react";
import Checkbox from "#material-ui/core/Checkbox";
import InputLabel from "#material-ui/core/InputLabel";
import ListItemIcon from "#material-ui/core/ListItemIcon";
import ListItemText from "#material-ui/core/ListItemText";
import MenuItem from "#material-ui/core/MenuItem";
import FormControl from "#material-ui/core/FormControl";
import Select from "#material-ui/core/Select";
import DeleteIcon from "#material-ui/icons/Delete";
import CreateIcon from "#material-ui/icons/Create";
import { MenuProps, useStyles, options as rawOptions } from "./utils";
function App() {
const classes = useStyles();
const [selected, setSelected] = useState([]);
const [options, setOptions] = useState(rawOptions)
const handleChange = (event) => {
console.log("vals", event.target);
const value = event.target.value;
setSelected(value);
console.log("values", selected);
};
return (
<FormControl className={classes.formControl}>
<InputLabel id="mutiple-select-label">Multiple Select</InputLabel>
<Select
labelId="mutiple-select-label"
multiple
variant="outlined"
value={selected || []}
onChange={handleChange}
renderValue={(selected) => selected}
MenuProps={MenuProps}
>
{options.map((option, index) => (
<MenuItem key={option.id} value={option}>
<ListItemIcon>
<Checkbox checked={selected?.includes(option)} />
</ListItemIcon>
<ListItemText primary={option.title}>{option}</ListItemText>
<DeleteIcon onClick={(e) => {
e.stopPropagation();
setOptions(options.filter(o => o !== option))
console.log('run');
}} />
<ListItemIcon>
<CreateIcon />
</ListItemIcon>
</MenuItem>
))}
</Select>
<p>{selected}</p>
</FormControl>
);
}
export default App;
You will need to declare another piece of state to represent options.
const [selectOptions, setSelectOptions] = useState(options);
Then from inside each element you could handle the delete or name change options by setting that state. For example, to handle deleting the element from the list:
{options.map((option, index) => (
...
<DeleteIcon
onClick={() =>
setSelectOptions((opts) => {
const newOpts = [...opts]; //create a shallow copy of selectOptions
newOpts.splice(index, 1); //remove the element at the current index
return newOpts;
})
}
/>
...
))}
This will push an update to the UI only. Additionally, if you wanted to also forever mutate the array options that you're importing from './utils', you could just include code inside the onClick event handler to make those updates as well.
Handling user input for changing the name is a little trickier, since you will also need to include a conditionally-displayed <TextField /> or similar for the user to perform the edits needed. You would probably also need to track some sort of state related to the editing process as well, something like:
const [isEditing, setIsEditing] = useState(false);
And then using that to conditionally render a text field.
<CreateIcon onClick={() => setIsEditing(true)} />
{isEditing && <TextField />}
That should hopefully get you started, from there you can also conditionally render a submit button, give it a onClick callback to update the selectOptions state, set the isEditing state back to false, and potentially mutate the original options array.
Good day everyone I'm trying to style the label text on the radio button to change to a blue color when selected.
THIS IS MY CODE OF THE MUI BUTTON SO FAR
import * as React from "react";
import Radio from "#mui/material/Radio";
import RadioGroup from "#mui/material/RadioGroup";
import FormControlLabel from "#mui/material/FormControlLabel";
import FormControl from "#mui/material/FormControl";
export default function RowRadioButtonsGroup({label1, label2}) {
return (
<FormControl>
<RadioGroup
row
aria-labelledby="demo-row-radio-buttons-group-label"
name="row-radio-buttons-group"
style={{display: 'flex', gap: '2rem'}}
sx={{
'& .MuiSvgIcon-root': {
fontSize: 28,
},
}}
>
<FormControlLabel value="Sunday" control={<Radio />} label={label1}/>
<FormControlLabel value="Monday" control={<Radio />} label={label2} />
</RadioGroup>
</FormControl>
);
}
Basically just create a styled form control label and use "useRadioGroup " hook button and choose the colors for checked and unchecked
https://codesandbox.io/s/radiobuttonsgroup-demo-material-ui-forked-pix9rg?file=/demo.js
// Custom label
const StyledFormControlLabel = styled((props) => (
<FormControlLabel {...props} />
))(({ theme, checked }) => ({
".MuiFormControlLabel-label": checked && {
// Change color here
color: "red"
}
}));
// Custom FormControl
function MyFormControlLabel(props) {
// MUI UseRadio Group
const radioGroup = useRadioGroup();
let checked = false;
if (radioGroup) {
checked = radioGroup.value === props.value;
}
return <StyledFormControlLabel checked={checked} {...props} />;
}
<MyFormControlLabel value="female" control={<Radio />} label="Female" />
I'm building a website that uses "RTL (Right To Left) language", so I implemented react-hook-form, but react hook form uses only "LTR" forms like so...
In here I'm using the HTML attribute (dir="RTL") in my page, so all the text is "RTL" except the react hook form how can I fix this?.
import { TextField, Grid } from "#material-ui/core";
import { useFormContext, Controller } from "react-hook-form";
const FormInput = ({ name, label }) => {
const { control } = useFormContext();
return (
<Grid item xs={12} sm={6}>
<Controller
as={TextField} control={control} fullWidth name={name} label={label} required defaultValue=""/>
</Grid>
)
}
export default FormInput;
this is my FormInput component, I export this component to my address form component
import { useForm, FormProvider } from "react-hook-form";
<FormProvider>
<form>
<FormInput name="firstName" label="الإسم الأول (first name)" />
<FormInput name="lastName" label="اسم العائلة (last name)" />
</form>
</FormProvider>
this is my address form component.
I'm using react-hook-form to handle form values, Its working fine for all other input types like TextFeild, Select from material but facing issues with "material-ui-chip-input" as adding tag working fine but not able to delete tag on click of cross button or hitting backspace. I'm struggling on this from a long. Anyone please help in it.
import React from "react";
import FormControl from "#material-ui/core/FormControl";
import { Controller } from "react-hook-form";
import ChipInput from "material-ui-chip-input";
const ReactHookFormChips = ({
name,
label,
control,
defaultValue,
children,
rules,
error,
chipsError,
...props
}) => {
const labelId = `${name}-label`;
return (
<FormControl {...props}>
<Controller
as={
<ChipInput
label={label}
helperText={chipsError}
error={error}
/>
}
name={name}
control={control}
defaultValue={defaultValue}
rules={rules}
/>
</FormControl>
);
};
export default ReactHookFormChips;
calling this component like
<ReactHookFormChips
id="levelLabel"
name="tags"
label="Select Tags"
control={control}
defaultValue={[]}
margin="normal"
error={!!errors?.tags}
rules={{ required: true }}
chipsError={errors?.tags && "Tag is required."}
/>
I fixed it using render prop.
import React from "react";
import FormControl from "#material-ui/core/FormControl";
import InputLabel from "#material-ui/core/InputLabel";
import { Controller } from "react-hook-form";
import ChipInput from "material-ui-chip-input";
const ReactHookFormChips = ({
name,
label,
control,
defaultValue,
children,
rules,
error,
chipsError,
...props
}) => {
const labelId = `${name}-label`;
return (
<FormControl {...props}>
<Controller
render={({ onChange, onBlur, value }) =>
<ChipInput
onChange={onChange}
label={label}
helperText={chipsError}
error={error}
/>
}
name={name}
control={control}
defaultValue={defaultValue}
rules={rules}
/>
</FormControl>
);
};
export default ReactHookFormChips;
I have an input field which I want a dollar sign to the left. I checked the docs and I tried to do it with InputAdornment but every time I did it, the dollar sign would never show up. Here's my code https://codesandbox.io/s/material-demo-wnei9?file=/demo.js
Instead of start adornment use the below code in the Input field.
InputProps={{
startAdornment: <InputAdornment position="start">$</InputAdornment>,
}}
You just imported the wrong Input.
In demo.js on line 5: import Input from "#material-ui/core/TextField";
The correct import would be: import Input from '#material-ui/core/Input';
Please change the 'value' attribute like this to get the symbol before the input.
<Input
className={classes.input}
value={"$" + value}
onChange={handleInputChange}
startAdornment={<InputAdornment position="start">A</InputAdornment>}
/>
Wrap them with Grid.
Change your code with this:
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import Typography from "#material-ui/core/Typography";
import Slider from "#material-ui/core/Slider";
import Input from "#material-ui/core/TextField";
import InputAdornment from "#material-ui/core/InputAdornment";
import Grid from "#material-ui/core/Grid";
import FormControl from "#material-ui/core/FormControl";
const useStyles = makeStyles({
root: {
width: 250
},
input: {
width: 100
}
});
export default function InputSlider() {
const classes = useStyles();
const [value, setValue] = React.useState(500);
const handleSliderChange = (event, newValue) => {
setValue(newValue);
};
const handleInputChange = event => {
setValue(event.target.value === "" ? "" : Number(event.target.value));
};
return (
<div className={classes.root}>
<Slider
min={500}
max={10000}
value={typeof value === "number" ? value : 0}
onChange={handleSliderChange}
aria-labelledby="input-slider"
/>
<FormControl fullWidth className={classes.margin}>
<Grid container spacing={2} alignItems="center">
<Grid item>$</Grid>
<Grid item>
<Input
className={classes.input}
value={value}
onChange={handleInputChange}
startAdornment={
<InputAdornment position="start">A</InputAdornment>
}
style={{ display: "inline-block" }}
/>
</Grid>
</Grid>
</FormControl>
</div>
);
}