MUI grid not stacking side by side in dynamic form - material-ui

This seems like a noob question, but for some reason, In my form, the grid is not stacking side by side when i set the prop to 6 IE md={6}. They all just set themselves to 6, and goto the next line. What i want, is for them to be side by side.
{fieldSet.map((item,index) => {
if(item.domain === null){
if(item.alias == 'OBJECTID'){
return
};
return (
<Grid xs={12} md={6} lg={6} key={index}>
<FormControl variant="standard" fullWidth style={{marginBottom:'10px'}}>
<InputLabel shrink multiline htmlFor={item.alias} style={{color:'white'}}>{item.alias}</InputLabel>
<StyledInput id={item.alias} onChange={e => setFieldsData(fieldsData => ({...fieldsData, [e.target.id]: e.target.value}))} />
</FormControl>
</Grid>
)
} else if(item.domain != null){
return (
<Grid xs={12} md={6} lg={6} key={index}>
<FormControl fullWidth size='small' style={{marginTop:'20px'}}>
<InputLabel id={item.alias}>{item.alias}</InputLabel>
<Select id={item.alias} labelId={item.alias} onChange={e => setFieldsData(fieldsData => ({...fieldsData, [item.alias]: e.target.value}))} style={{backgroundColor:'white'}}>
{item.domain.codedValues.map((values, index) => {
return (
<MenuItem key={index} value={values.name}>{values.name}</MenuItem>
)
})}
</Select>
</FormControl>
</Grid>
)
}
})}

Related

Radio Buttons with own labels/components (Material UI)

I would like to have my own component for my specific radio button. But the component doesn't render correctly.
I have a RadioGroup like this:
const SampleComp = (props : MyProps) => {
return <RadioGroup
defaultValue="AllTime"
name="Filter"
>
<FormControlLabel value="AllTime" control={<Radio />} label="All time" />
<FormControlLabel value="TestLabel" control={<Radio />} label={<TestLabel/>} />
</RadioGroup>
}
And I have a Testlabel to show a select component:
const TestLabel = () => {
return <FormControl fullWidth variant={'outlined'}>
<InputLabel id="demo-simple-select-label">Long text for label</InputLabel>
<Select
labelId="myField"
id="myField"
label="Long text for label"
onChange={handleChange}
>{[0, 1, 2, 3, 4, 5, 6].map(s => <MenuItem key={s} value={s}>{'value ' + s}</MenuItem>)}
</Select>
</FormControl>
}
In the end it looks like this:
I expected something like this:
Question: How can I render my component correctly when using in combination with a radio button? Or should this be done differently?
I messed around trying to get something to work but it doesn't look possible + the docs for FormControlLabel say it should take A control element. For instance, it can be a Radio, a Switch or a Checkbox.
It looks like you need to render a RadioGroup with an 'other' option and then either dynamically render or undisable a dropdown underneath the RadioGroup to achieve the behaviour you're after.
const SampleComp = () => {
const [selectedRadioValue, setSelectedRadioValue] = useState('AllTime')
const [selectedMenuItem, setSelectedMenuItem] = useState<string>()
return (
<>
<RadioGroup
value={selectedRadioValue}
name="Filter"
onChange={(_event, newValue) => setSelectedRadioValue(newValue)}
>
<FormControlLabel value="AllTime" control={<Radio />} label="All time" />
<FormControlLabel value="Other" control={<Radio />} label="Other" />
</RadioGroup>
<TextField
disabled={selectedRadioValue !== 'Other'}
label="Long text for label"
value={selectedMenuItem}
onChange={(event) => setSelectedMenuItem(event.target.value)}
fullWidth
select
>
{[0, 1, 2, 3, 4, 5, 6].map((s) => (
<MenuItem key={s} value={s}>
{'value ' + s}
</MenuItem>
))}
</TextField>
</>
)
}

MUI dropdown react application

I am using MUI to develop my dashboard.
I am using MUI dropdown component to select the vendor details and there are two options for the Vendor dropdown. i.e "Surya Kumar Yadav", "Eswar". I used the same dropdown in all my cards. When I select the one of the dropdown in any card, it is reflected in all the other cards.
import React from "react";
import {
Box,
Card,
CardContent,
Typography,
Button,
CardActionArea,
CardActions,
Grid,
Select,
MenuItem,
FormControl,
InputLabel,
} from "#mui/material";
import { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { HttpClient } from "../http/http";
import { ConfirmDialog, confirmDialog } from "./ConfirmDialog";
const Services = () => {
const [services, setServices] = useState([]);
const [vendors, setVednors] = useState([]);
const [selectedVendor, setSelectedVendor] = useState("");
const PF =
"https://firebasestorage.googleapis.com/v0/b/mern-stack-service-app.appspot.com/o/";
const navigate = useNavigate();
useEffect(() => {
init();
}, []);
const init = () => fetchServices();
const fetchServices = async () => {
const services = await HttpClient.get(`services`);
const vendors = await HttpClient.get(`vendor`);
setVednors(vendors);
setServices(services);
};
const handleChange = (event) => {
setSelectedVendor(event.target.value);
};
console.log(services);
return services.length === 0 ? (
<Grid>
<Typography
sx={{
fontSize: 32,
color: "blue",
display: "flex",
justifyContent: "center",
alignItems: "center",
textDecoration: "underline",
}}
>
Loading your services.....
</Typography>
</Grid>
) : (
<Grid container>
<ConfirmDialog />
<Grid container item xs={12} columnGap={2}>
<Box sx={{ float: "right" }}>
<Button
variant="outlined"
onClick={() => {
confirmDialog("Are you sure want to logout?", () => {
localStorage.clear();
navigate("/login");
});
}}
>
Logout
</Button>
</Box>
</Grid>
<Grid container item xs={12} rowGap={2}>
{services.map((service, index) => (
<Grid item xs={12} sm={6} md={4} key={index}>
<Card>
<CardActionArea>
<CardContent>
<Grid
component="img"
sx={{
height: 150,
width: 350,
maxHeight: { xs: 150, md: 175 },
maxWidth: { xs: 350, md: 375 },
objectFit: "cover",
}}
alt="The house from the offer."
src={
PF +
service.photo +
"?alt=media&token=c19f2d0a-f254-4391-b589-ef7ee3cad9f5"
}
></Grid>
<Grid item xs={12}>
<Typography textAlign="center">
{service.service}
</Typography>
</Grid>
<Grid item xs={12}>
<FormControl sx={{ minWidth: 120 }} size="small" fullWidth>
<InputLabel id="demo-select-small">
Select Vendor
</InputLabel>
<Select
size="small"
labelId="demo-select-small"
id="demo-select-small"
value={selectedVendor}
label="Select Vendor"
onChange={handleChange}
>
{vendors.map((vendor) => (
<MenuItem
key={vendor._id}
value={vendor.name}
id={vendor.name}
>
{vendor.name}
</MenuItem>
))}
</Select>
</FormControl>
</Grid>
</CardContent>
</CardActionArea>
<CardActions>
<Grid item xs={12}>
<Button variant="outlined" color="primary" fullWidth>
Book Service
</Button>
</Grid>
</CardActions>
</Card>
</Grid>
))}
</Grid>
</Grid>
);
};
export default Services;
I want the dropdown action reflect in the selected card.
It's because all of your mapped Select elements get their value from selectedVendor. you can change the code like this using these steps:
First:
Change the selectingVendor useState like this:
const [selectedVendors, setSelectedVendors] = useState([]);
Second:
And the handleChange function
const handleChange = (event,index) => {
const currentSelectedVendors = [...selectedVendors];
currentSelectedVendors[index] = event.target.value
setSelectedVendors(currentSelectedVendors);
};
Third:
You need to change the Select Mui component props.
<Select
size="small"
labelId="demo-select-small"
id="demo-select-small"
value={selectedVendors[index] || ""}
label="Select Vendor"
onChange={(e) => handleChange(e,index)}
>
Although there is another solution for this problem and you can pull <Select> logic out of Services component , I mean it's selectingVendor hook and it's change handler and create a new separate component which handles it.
PS: I think it should be better to use vendor._id as the value prop of your MenuItems

#mui grid items of equal height

Using the React #mui package, I want to create a grid of items that all stretch to the same height as the tallest item. I've tried searching for similar questions but have not found a working solution, and using #mui v5. Here's my example, also found on Sandbox https://codesandbox.io/s/happy-moon-y5lugj?file=/src/App.js. I prefer a solution (if possible) using the #mui components rather than grid css directly. Also I cannot fix the number of columns, it needs to be responsive.
import * as React from "react";
import {
Box,
Card,
Container,
Grid,
Paper,
Table,
TableBody,
TableRow,
TableCell,
Typography
} from "#mui/material";
export default function App() {
const createTable = (rows) => {
return (
<Table>
<TableBody>
{[...Array(rows).keys()].map((n) => {
return (
<TableRow key={n}>
<TableCell>Aaaaa</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
);
};
return (
<Box p={3}>
<Container maxWidth="sm" height="100%">
<Grid container spacing={2} height="100%">
<Grid item height="100%">
<Paper height="100%" elevation={3} sx={{ p: 3 }}>
<Typography variant="h4">Something</Typography>
{createTable(5)}
</Paper>
</Grid>
<Grid item height="100%">
<Paper height="100%" elevation={3} sx={{ p: 3 }}>
<Typography variant="h4">More things</Typography>
{createTable(3)}
</Paper>
</Grid>
</Grid>
</Container>
</Box>
);
}
This is what I get now. I want the shorter item to be padded on the bottom so its the same height as the first.
Please use this code from the box downwards. You can read more about how to work with grid items on the mui website here.
const StackOverflow = () => {
const createTable = (rows) => {
return (
<Table>
<TableBody>
{[...Array(rows).keys()].map((n) => {
return (
<TableRow key={n}>
<TableCell>Aaaaa</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
);
};
return (
<Box p={3}>
<Container maxWidth="sm">
<Grid container spacing={2}>
<Grid item xs={6}>
<Paper elevation={3} sx={{ p: 3, height: "100%" }}>
<Typography variant="h4">Something</Typography>
{createTable(5)}
</Paper>
</Grid>
<Grid item xs={6}>
<Paper elevation={3} sx={{ p: 3, height: "100%" }}>
<Typography variant="h4">More things</Typography>
{createTable(3)}
</Paper>
</Grid>
</Grid>
</Container>
</Box>
);
};
Something that worked good for me was to use the following in the Papers sx prop:
{{height: "100%", display: "flex", alignItems: "center"}}

Fix dialog material ui

I have a dialog with material ui where i have a text and then 4 fields textfield.
The problem is that the elements inside dialogcontent doesnt fill all the space in the dialog leaving one blank space on the right side.
I would like to give some space between the textfields in the same row as well as space-evenly these elements.
This is my dialog definition:
import React from "react";
import Dialog from "#material-ui/core/Dialog";
import DialogTitle from "#material-ui/core/DialogTitle";
import {
DialogActions,
Button,
DialogContent,
DialogContentText,
} from "#material-ui/core";
import { faExclamationTriangle } from "#fortawesome/free-solid-svg-icons";
import { addProduct } from "../view/Items/Items";
import { useState } from "react";
import { TextField } from "#material-ui/core";
import { updateValues } from "../view/Items/Items";
import { Grid } from "#material-ui/core";
export default function AlertPopOverParametros({
producto,
año,
open,
setOpen,
onAccept,
}) {
const [coef_transp, setCoefTransp] = useState();
const [coef_comer, setCoefComer] = useState();
const [km, setKm] = useState();
const [prod, setProd] = useState();
return (
<Dialog fullWidth aria-labelledby="simple-dialog-title" open={open}>
<DialogTitle id="simple-dialog-title">
<b>Configuración del producto</b>
</DialogTitle>
<DialogContent>
<DialogContentText>
Introduzca los valores necesarios para el cálculo del valor de huella
hídrica
</DialogContentText>
<TextField
onChange={(e) => setCoefTransp(e.target.value)}
autoFocus
label="Coeficiente de Transporte"
type="number"
value={coef_transp}
/>
<TextField
onChange={(e) => setCoefComer(e.target.value)}
autoFocus
label="Coeficiente de Comercialización"
type="number"
value={coef_comer}
/>
<TextField
onChange={(e) => setKm(e.target.value)}
autoFocus
label="Kilómetros"
type="number"
value={km}
/>
<TextField
onChange={(e) => setProd(e.target.value)}
autoFocus
label="Producción"
type="number"
value={prod}
/>
</DialogContent>
<DialogActions>
{onAccept ? (
<Button
style={{
backgroundColor: "#0068ff",
color: "white",
borderRadius: "5px",
}}
fullWidth
onClick={() => {
onAccept();
console.log(producto, año, coef_transp, coef_comer, km, prod);
updateValues(producto, año, coef_transp, coef_comer, km, prod);
setOpen(false);
}}
>
Aceptar
</Button>
) : null}
</DialogActions>
</Dialog>
);
}
I have tried to wrap everything in a Grid element and specifying the size of it but it didn't work.
Thank you so much.
Using a Grid and fullWidth property on the Textfields will solve your issue:
<Grid container>
<Grid xs={6}>
<TextField
fullWidth
...
/>
</Grid>
<Grid xs={6}>
<TextField
fullWidth
...
/>
</Grid>
<Grid xs={6}>
<TextField
fullWidth
...
/>
</Grid>
<Grid xs={6}>
<TextField
fullWidth
...
/>
</Grid>
</Grid>
The Grid will order the textfields into two rows and two columns by setting xs to 6 on the grid childs. Then in order to make your textfields span the entire width of the grid child you can use the fullWidth property.

material-ui autocomplete wrapped into react-hook-form Controller, can't get the value

I can't get the value of the field wrapped into the react-hook-form <Controller /> in the onSubmit function. What is missing?
the other field works correctly
const onSubmit = async (data,e) => {
console.log("DATA" , data)
//data.groups is always undefined
...
}
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="groups"
control={control}
as={() => (
<Autocomplete multiple options={fbGroupsData.Group} getOptionLabel={option => option.name} renderInput={(params) =>(<TextField {...params} variant="outlined" label="Groups" placeholder="Groups" />)}/>
)}
/>
<TextField fullWidth inputRef={register} InputLabelProps={{ shrink: true }} name="name" label="Name" variant="outlined" />
</form>
There is an example in the doc: https://codesandbox.io/s/react-hook-form-v6-controller-qsd8r which was recommended to use render prop instead of as:
<Controller
render={(props) => (
<Autocomplete
{...props}
options={countries}
getOptionLabel={(option) => option.label}
renderOption={(option) => (
<span>
{countryToFlag(option.code)}
{option.label}
</span>
)}
renderInput={(params) => (
<TextField
{...params}
label="Choose a country"
variant="outlined"
/>
)}
onChange={(_, data) => props.onChange(data)}
/>
)}
name="country"
control={control}
/>