setValue from material UI select - javascript

I have created a dropdown menu
const [splittingMethod, setSplittingMethod] = useState('');
const handleChange = (e: any) => {
//setSplittingMethod(e)
console.log('value', splittingMethod)
}
....
<FormControl variant="filled" >
<InputLabel id="demo-simple-select-filled-label" className={classes.field}>Splitting Method</InputLabel>
<Select
labelId="demo-simple-select-filled-label"
id="demo-simple-select-filled"
value={splittingMethod}
onChange={(e)=>handleChange(e)}
>
<MenuItem value="random">
Random
</MenuItem>
<MenuItem value={'timeEnd'}>Time End</MenuItem>
<MenuItem value={'slidingWindow'}>Sliding Window</MenuItem>
</Select>
</FormControl>
and I want to save the selected item's value into the splittingMethod variable. How can I achieve this? My current method would give me an error:
react-dom.development.js:13231 Uncaught Error: Objects are not valid as a React child

You have to access e.target.value to get the value
import React, { useState } from "react";
import { FormControl, InputLabel, Select, MenuItem } from "#material-ui/core";
const App = () => {
const [splittingMethod, setSplittingMethod] = useState("");
const handleChange = (
e: React.ChangeEvent<{
name?: string | undefined;
value: unknown;
}>
) => {
// type checking
const value = typeof e.target.value === "string" ? e.target.value : "";
setSplittingMethod(value);
};
return (
<FormControl variant="filled" style={{ width: "100%" }}>
<InputLabel
id="demo-simple-select-filled-label"
style={{ width: "100%" }}
>
Splitting Method
</InputLabel>
<Select
labelId="demo-simple-select-filled-label"
id="demo-simple-select-filled"
value={splittingMethod}
onChange={handleChange}
>
<MenuItem value="random">Random</MenuItem>
<MenuItem value={"timeEnd"}>Time End</MenuItem>
<MenuItem value={"slidingWindow"}>Sliding Window</MenuItem>
</Select>
</FormControl>
);
};
export default App;
Live demo

Related

How to clear data on Select multiple when typing on another textfield using reactjs

This is my current code, what I want here is after selecting on Select option (CHIP) and if the user type on the textfield I want to clear what the user selected on CHIP, What should I do to get what i want functionality?
const names = [
'Oliver Hansen',
'Van Henry',
'April Tucker',
];
function getStyles(name, personName, theme) {
return {
fontWeight:
personName.indexOf(name) === -1
? theme.typography.fontWeightRegular
: theme.typography.fontWeightMedium,
};
}
export default function MultipleSelectChip() {
const theme = useTheme();
const [personName, setPersonName] = React.useState([]);
const handleChange = (event) => {
const {
target: { value },
} = event;
setPersonName(
// On autofill we get a stringified value.
typeof value === 'string' ? value.split(',') : value
);
};
const handleChangeTextField = (event) => {
setPersonName(null);
};
return (
<div>
<FormControl sx={{ m: 1, width: 300 }}>
<InputLabel id="demo-multiple-chip-label">Chip</InputLabel>
<Select
labelId="demo-multiple-chip-label"
id="demo-multiple-chip"
multiple
value={personName}
onChange={handleChange}
input={<OutlinedInput id="select-multiple-chip" label="Chip" />}
renderValue={(selected) => (
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5 }}>
{selected.map((value) => (
<Chip key={value} label={value} />
))}
</Box>
)}
MenuProps={MenuProps}
>
{names.map((name) => (
<MenuItem
key={name}
value={name}
style={getStyles(name, personName, theme)}
>
{name}
</MenuItem>
))}
</Select>
<TextField
variant="outlined"
label="Type anything to remove the value of Chip"
onChange={handleChangeTextField} />
</FormControl>
</div>
This is my current code, what I want here is after selecting on Select option (CHIP) and if the user type on the textfield I want to clear what the user selected on CHIP, What should I do to get what i want functionality?
I would set your textfield to be controlled (ie backed by a state variable) and add an effect hook to watch it.
When it receives a value, clear the selected names by setting personNames back to an empty array.
const [text, setText] = useState("");
useEffect(() => {
if (text) {
setPersonName([]);
}
}, [text]);
const handleChangeTextField = ({ target: { value } }) => {
setText(value);
};
<TextField
value={text}
variant="outlined"
label="Type anything to remove the value of Chip"
onChange={handleChangeTextField}
/>
You might also want to clear the text field when selecting names by adding this into handleChange...
setText("");

How do I create dynamic select fields?

I have these 2 fields size and design in which the user can add more of these 2 fields as many times as they want.
Example:
I selected M for the size. It does show in the console:
Additionally, why is it rendering two of size and design at the first load of the screen? Also, add
And now selecting a design:
It will remove the value that was previously selected in the size field.
And in the console, the value of size has been replaced with design2
codesandbox link: https://codesandbox.io/s/form-1-ls6rx?file=/demo.js
import React, { useState, useEffect } from "react";
import Box from "#mui/material/Box";
import InputLabel from "#mui/material/InputLabel";
import MenuItem from "#mui/material/MenuItem";
import FormControl from "#mui/material/FormControl";
import Select from "#mui/material/Select";
import { TextField, Button } from "#mui/material";
export default function BasicSelect() {
const [prod, setProd] = useState("");
const [qty, setQty] = useState(0);
const [design, setDesign] = useState("");
const [sizeList, setSizeList] = useState([{ size: "", design: "" }]);
const handleChange = (event) => {
setProd(event.target.value);
};
const handleSubmit = async (e) => {
e.preventDefault();
console.log(prod, qty, sizeList, design);
};
//helper method
const handleAdd = () => {
setSizeList([...sizeList, { size: "", design: "" }]);
};
const handleRemove = (index) => {
const list = [...sizeList];
list.splice(index, 1);
setSizeList(list);
};
const handleSizeChange = (e, index) => {
const { value } = e.target;
setSizeList((prev) =>
Object.assign([...prev], {
[index]: { size: value }
})
);
};
useEffect(() => {
console.log(sizeList);
}, [sizeList]);
return (
<Box sx={{ minWidth: 120 }}>
<form onSubmit={handleSubmit}>
<FormControl fullWidth>
<InputLabel id="demo-simple-select-label">Product</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={prod}
label="Product"
onChange={handleChange}
>
<MenuItem value="Item1">Item1</MenuItem>
<MenuItem value="Item2">Item2</MenuItem>
<MenuItem value="Item3">Item3</MenuItem>
</Select>
</FormControl>
<br />
<br />
<br />
<br />
{sizeList.map((singleSize, index) => (
<div key={index}>
<FormControl fullWidth>
<InputLabel id="demo-simple-select-label">Size</InputLabel>
<Select
labelId="demo-simple-select-label"
id="size"
value={singleSize.size}
label="Product"
onChange={(e) => handleSizeChange(e, index)}
>
<MenuItem value="S">Small</MenuItem>
<MenuItem value="M">Medium</MenuItem>
<MenuItem value="L">Large</MenuItem>
</Select>
</FormControl>
<FormControl fullWidth>
<InputLabel id="demo-simple-select-label">
Choose Design
</InputLabel>
<Select
labelId="demo-simple-select-label"
id="design"
value={singleSize.design}
label="Product"
onChange={(e) => handleSizeChange(e, index)}
>
<MenuItem value="Design1">Design1</MenuItem>
<MenuItem value="Design2">Design2</MenuItem>
<MenuItem value="Design3">Design3</MenuItem>
</Select>
</FormControl>
<br />
<br />
{sizeList.length > 1 && (
<Button
onClick={() => handleRemove(index)}
variant="contained"
color="secondary"
>
Remove{" "}
</Button>
)}
<br />
<br />
{sizeList.length - 1 === index && (
<Button variant="contained" onClick={handleAdd}>
{" "}
Add Quantity
</Button>
)}
</div>
))}
<br />
<br />
<br />
<br />
<Button type="submit">Submit </Button>
</form>
<Button>Add more Product </Button>
</Box>
);
}
You are using the same handler that is supposed to handle and update states for both the design and size, also there lies a problem in how you are updating the state using Object.assign, this is also leading to additional warnings in the console regarding the value passed, the issue is most likely due to the event conflict.
To put things in place, simply use different handlers to handle updates of different object attributes. A simple solution is to create a new array, make the necessary updates and set the new array to be the updated state, I tested this and it works as expected.
const handleSizeChange = (e, index) => {
const { value } = e.target;
console.log(value)
const arr = [...sizeList] //Shallow copy the existing state
arr[index].size = value //Update the size to the selected size
setSizeList([...arr]); //Set the updated array to be the new state
};
Add a new handler for updating the design value.
const handleDesignChange = (e,index)=>{
const { value } = e.target;
console.log(value)
const arr = [...sizeList]
arr[index].design = value
// console.log(arr)
setSizeList([...arr]);
}
Alternatively, you could club both the handlers into a single handler by adding conditional checks.

React Autocomplete with Material UI

I'm implementing a component Autocomplete using Material UI library.
But there's a problem - I'm not sure how to pass value and onChange properly, because I have a custom implementation of TextField that requires value and onChange as well. Should I pass value and onChange twice - to Autocomplete and TextField? Or maybe there's a better solution? Would appreciate any help!
Here's my code:
import { Autocomplete as MuiAutocomplete } from '#material-ui/lab'
import { FormControl } from 'components/_helpers/FormControl'
import { useStyles } from 'components/Select/styles'
import { Props as TextFieldProps, TextField } from 'components/TextField'
export type Props = Omit<TextFieldProps, 'children'> & {
options: Array<any>
value: string
onChange: (value: string) => void
disabled?: boolean
}
export const Autocomplete = (props: Props) => {
const classes = useStyles()
return (
<FormControl
label={props.label}
error={props.error}
helperText={props.helperText}
>
<MuiAutocomplete
options={props.options}
// value={props.value}
// onChange={event =>
// props.onChange((event.target as HTMLInputElement).value as string)
// }
classes={{
option: classes.menuItem,
}}
disabled={props.disabled}
getOptionLabel={option => option.label}
renderInput={params => (
<TextField
{...params}
placeholder={props.placeholder}
value={props.value}
onChange={props.onChange}
/>
)}
renderOption={option => {
return <Typography>{option.label}</Typography>
}}
/>
</FormControl>
)
}```
Material UI has props built in to handle the state of the Autocomplete vs input values.
You can see it in use in the docs here: https://material-ui.com/components/autocomplete/#controllable-states
In your example, you would want to add the inputChange and onInputChange props to the Autocomplete component. These will get passed down to your TextField through the params passed to the renderInput function.
So your final code would look something like the below snippet copied from the linked documentation:
<Autocomplete
value={value}
onChange={(event, newValue) => {
setValue(newValue);
}}
inputValue={inputValue}
onInputChange={(event, newInputValue) => {
setInputValue(newInputValue);
}}
id="controllable-states-demo"
options={options}
style={{ width: 300 }}
renderInput={(params) => <TextField {...params} label="Controllable" variant="outlined" />}
/>
import React, { useEffect, useState } from "react";
import { Autocomplete } from "#mui/material/node";
import { Controller, useFormContext } from "react-hook-form";
import { TextField } from "#mui/material";
import PropTypes from "prop-types";
const valueFunc = (arr, id) => {
const temp = arr.length > 0 && arr?.find((element) => element.id === id);
return temp;
};
AutocompleteSearch.propTypes = {
options: PropTypes.arrayOf({
title: PropTypes.string,
id: PropTypes.string,
}),
name: PropTypes.string,
};
export default function AutocompleteSearch({
name,
options,
label,
id,
...other
}) {
const [temp, setTemp] = useState({});
const { control, setValue } = useFormContext();
useEffect(async () => {
const found = valueFunc(options, id);
await setTemp(found);
}, [options, id]);
return (
<Controller
control={control}
name={name}
rules={{ required: true }}
render={({ fieldState: { error } }) => (
<>
<div >
<Autocomplete
id="controllable-states-demo"
onChange={(_, v) => {
setValue(name, v?.id);
setTemp(v);
}}
onBlur={(e) => {
e.target.value == "" && setValue(name, "");
}}
value={temp}
options={options}
getOptionLabel={(item) => (item.title ? item.title : "")}
renderInput={(params) => (
<>
<TextField
{...params}
label={label}
InputLabelProps={{
style: {
fontSize: "14px",
fontWeight: "400",
color: "#FF5B00",
},
}}
size="small"
error={temp === null && !!error}
helperText={temp === null && error?.message}
{...other}
/>
</>
)}
/>
</div>
</>
)}
/>
);
}
<AutocompleteSearch
name="pharmacy_group_title"
label="Pharmacy Group"
options={pharmacyGroups} // Array {id , title}
id={defaultValues?.pharmacy_group_title} // ID
/>

State is empty even have setted up with data

I am trying to fetch the data from the database and storing it in a state but when I console log my state, no data has been stored in the state but when I console the data itself, it returns what I expected to have. This is my code;
import React, { useContext, useEffect, useState } from 'react';
import { Field, Form, Formik, useField } from 'formik';
import * as Yup from 'yup';
import {
Button,
Box,
makeStyles,
Grid,
Typography,
Divider,
FormHelperText,
Select,
MenuItem,
InputLabel,
FormControl,
} from '#material-ui/core';
import {
MuiPickersUtilsProvider,
KeyboardDateTimePicker,
} from '#material-ui/pickers';
import DateFnsUtils from '#date-io/date-fns';
import 'date-fns';
// Yup validation Schema
const validationSchema = Yup.object().shape({
date: Yup.date().required('Please enter valid date').nullable(),
teamOne: Yup.string().required('Please select team'),
teamTwo: Yup.string().required('Please select team'),
});
// This is a custom date field using Formik
const DateTimeField = ({ field, form, ...props }) => {
const currentError = form.errors[field.name];
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardDateTimePicker
clearable
disablePast
name={field.name}
value={field.value}
format="MM/dd/yyyy"
helperText={currentError}
error={!!currentError}
onError={(error) => {
if (error !== currentError) {
form.setFieldError(field.name, error);
}
}}
onChange={(date) => form.setFieldValue(field.name, date, true)}
{...props}
/>
</MuiPickersUtilsProvider>
);
};
// Custom <Select> field
const TeamSelection = ({ name, ...props }) => {
const [field, meta] = useField(name);
const errorText = meta.error && meta.touched ? meta.error : '';
return (
<>
<Select
name={field.name}
{...field}
fullWidth
error={!!errorText}
{...props}
>
{props.children}
</Select>
<FormHelperText error>{errorText}</FormHelperText>
</>
);
};
export default function AddMatch() {
const classes = useStyles();
const fetchContext = useContext(FetchContext);
const [team, setTeam] = useState([]);
useEffect(() => {
const getTeam = async () => {
try {
const { data } = await fetchContext.authAxios.get('get-all-teams');
setTeam(data);
} catch (error) {
console.log(error);
}
};
getTeam();
}, [fetchContext]);
console.log(team);
return (
<Formik
initialValues={{ date: new Date(), teamOne: '', teamTwo: '' }}
validationSchema={validationSchema}
onSubmit={(values) => {
if (values.teamOne === values.teamTwo) {
return console.log('Teams must not be the same!');
}
return console.log(values);
}}
>
{() => (
<Form noValidate>
<Grid>
<Typography>
Add Match
</Typography>
</Grid>
<Divider />
<Box>
<Grid>
<Grid>
<Field
name="date"
label="Set date and time"
component={DateTimeField}
/>
</Grid>
<Grid>
<Grid>
<FormControl>
<InputLabel>
Team A
</InputLabel>
<TeamSelection name="teamOne">
<MenuItem value=""> </MenuItem>
{team.map((item) => (
<MenuItem value={item.teamName} key={item._id}>
{item.teamName}
</MenuItem>
))}
</TeamSelection>
</FormControl>
</Grid>
<Grid>
<FormControl>
<InputLabel>
Team B
</InputLabel>
<TeamSelection name="teamTwo">
<MenuItem value=""> </MenuItem>
{team.map((item) => (
<MenuItem value={item.teamName} key={item._id}>
{item.teamName}
</MenuItem>
))}
</TeamSelection>
</FormControl>
</Grid>
</Grid>
<Box>
<Button type="submit">
Submit
</Button>
</Box>
</Grid>
</Box>
</Form>
)}
</Formik>
)}
I'm using Material UI and Formik.
It only logged an empty array "[]" or it makes an error, (.map is not a function). I tried to set the state as an Object but there is still no data being stored with the state.
Check the post request in your res.status(200).json() or res.send() or res.json(). Don't use brackets inside .json() or .send(), in your res or response, for example:
.json({}) // Don't use brackets if you don't want to send your data as an Object
If ever you want it to be object, then call the array which is called data like
useEffect(() => {
const getTeam = async () => {
try {
const { teamsData } = await fetchContext.authAxios.get('get-all-teams');
setTeam(teamsData.data);
} catch (error) {
console.log(error);
}
};
getTeam();
}, [fetchContext]);
destructure the teamsData if you have passed it as an Object on purpose.

How to set the default item in the drop-down menu?

How can I display the default value in the drop-down list using material-ui? I tried to add displayEmpty="true", but nothing changed.
I would like to have the first option A selected by default, so that a user can see it in UI. Currently, a user should click on the drop-down menu in order to select an item from the list. No item is selected by default (the selected item is blank by default).
const options = [
{label:"A",value:483.93},
{label:"B",value:8033.86},
{label:"C",value:1246.3}
]
<Grid item xs={true}>
<FormControl
className={this.props.styles.formControl}
margin="normal">
<InputLabel shrink htmlFor="distanceTarget-label-placeholder">
Target:
</InputLabel>
<Select
onChange={(event) => this.props.handleChange("distanceTarget", event)}
value={this.props.state.distanceTarget}
input={<Input name="distanceTarget" id="distanceTarget-label-placeholder" />}
displayEmpty="true"
name="distanceTarget"
>
{options && options.length && options.map((option, i) => {
return <MenuItem value={option.value} key={i}>{option.label}</MenuItem>
})}
</Select>
</FormControl>
</Grid>
UPDATE:
This is what I tried as suggested in comments, however I still have the same issue:
{options && options && options((option, i) => {
if (i===0) {
return <MenuItem value={option.value} key={i} selected={true}>{option.label}</MenuItem>
}
else {
return <MenuItem value={option.value} key={i}>{option.label}</MenuItem>
}
})}
Try this one. Add displayEmpty not displayEmpty="true".
<Select
onChange={(event) => this.props.handleChange("distanceTarget", event)}
value={this.props.state.distanceTarget}
input={<Input name="distanceTarget" id="distanceTarget-label-placeholder" />}
renderValue={value => ${value}`} // you should add your default value here
name="distanceTarget"
Render the selected value. You can only use it when the native prop is false (default). (material-ui docs)
In order to have a particular item selected by default, you should initialize the state that control's the Select's value to have that item's value. For instance, in my modified version of your code, I am initializing the Select's value to options[0].value.
import React from "react";
import ReactDOM from "react-dom";
import {
FormControl,
Input,
InputLabel,
Select,
MenuItem
} from "#material-ui/core";
const options = [
{ label: "A", value: 483.93 },
{ label: "B", value: 8033.86 },
{ label: "C", value: 1246.3 }
];
function App() {
const [distanceTarget, setDistanceTarget] = React.useState(options[0].value);
return (
<FormControl margin="normal">
<InputLabel shrink htmlFor="distanceTarget-label-placeholder">
Target:
</InputLabel>
<Select
onChange={event => setDistanceTarget(event.target.value)}
value={distanceTarget}
input={
<Input name="distanceTarget" id="distanceTarget-label-placeholder" />
}
name="distanceTarget"
>
{options &&
options.length &&
options.map((option, i) => {
return (
<MenuItem value={option.value} key={i}>
{option.label}
</MenuItem>
);
})}
</Select>
</FormControl>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Categories

Resources