I am trying to make a file upload form (front-end), but I don't think my uploaded file is communicating with the initial values when submitting since only the dataset name and the contact email are changed when I try to submit the form.
Here is what the form looks like when I load the page:
I initially press submit to see what happens within the React console tools. The output looks like this Subscribe form values: {datasetName: "dataset.csv", contactEmail: "johndoe#example.com", uploadFile: "sample.csv"} which is expected.
I then change the name of the dataset, change the contact email, and choose a file.
Unfortunately, the output looks like this Subscribe form values: {datasetName: "newData.csv", contactEmail: "janedoe#example.com", uploadFile: "sample.csv"}. Notice how the uploadFile part is the same despite trying to change the values.
I am fairly new to React, and I am using Material UI to render some of the textfields and buttons. What am I missing here?
import React from 'react';
import { Form } from 'react-final-form';
import { TextField } from 'mui-rff';
import { makeStyles } from '#material-ui/core/styles';
import Button from '#material-ui/core/Button';
import Grid from '#material-ui/core/Grid';
import Input from '#material-ui/core/Input';
import { FormControl } from '#material-ui/core';
import axios from 'axios';
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
padding: theme.spacing(2)
},
}));
const onSubmit = async values => {
console.log('Subscribe form values:', values);
};
const validate = values => {
const errors = {};
if (!values.datasetName) {
errors.datasetName = 'Required';
}
if (!values.contactEmail) {
errors.contactEmail = 'Required';
}
if (!values.uploadFile) {
errors.uploadFile = 'Required';
}
return errors;
};
const UploadForm = () => {
const classes = useStyles();
return (
<div className={classes.root}>
<Form
onSubmit={onSubmit}
initialValues={{ datasetName: 'dataset.csv', contactEmail: 'johndoe#example.com', uploadFile: 'sample.csv' }}
validate={validate}
render={({ handleSubmit, form, submitting, pristine, values }) => (
<form onSubmit={handleSubmit} noValidate>
<Grid
container
justify="center"
alignItems="center"
spacing={2}>
<Grid item xs={12}>
<TextField
label="Dataset Name"
name="datasetName"
margin="none"
required={true}
/>
</Grid>
<Grid item xs={12}>
<TextField
label="Contact Email"
name="contactEmail"
margin="none"
required={true}
/>
</Grid>
<Grid item xs={12}>
<FormControl>
<Input
name='uploadFile'
type='file'
required={true}
/>
</FormControl>
</Grid>
<Grid item xs={12}>
<Button
variant="contained"
color="primary"
type="submit"
disabled={submitting}
>
Submit
</Button>
</Grid>
</Grid>
</form>
)}
/>
</div>
);
}
export default UploadForm;
Imports:
import React from 'react';
import { Form } from 'react-final-form';
import { TextField } from 'mui-rff';
import { makeStyles } from '#material-ui/core/styles';
import Button from '#material-ui/core/Button';
import Grid from '#material-ui/core/Grid';
import Input from '#material-ui/core/Input';
import { FormControl } from '#material-ui/core';
import axios from 'axios';
Related
I am new to ReactJS with MUI development, have below ReactJS TypeScript with MuiText filed form. Looking some help to use useSate method to change the textfiled value.
Also add the onchnage function for the text filed. I can add the onchange function for normal text filed, unsure how to add it for MUI Text filed?
import * as React from 'react';
import { useState } from "react"
import Button from '#mui/material/Button';
import CssBaseline from '#mui/material/CssBaseline';
import TextField from '#mui/material/TextField';
import Grid from '#mui/material/Grid';
import Box from '#mui/material/Box';
import Container from '#mui/material/Container';
import { createTheme, ThemeProvider } from '#mui/material/styles';
import { useForm, SubmitHandler, Controller } from 'react-hook-form';
import * as yup from 'yup';
import { yupResolver } from '#hookform/resolvers/yup';
interface IFormInputs {
filepath: string;
}
const schema = yup.object().shape({
filepath: yup.string().min(4).required(),
});
const theme = createTheme();
export default function MuiTextField() {
const {
control,
handleSubmit,
formState: { errors },
} = useForm<IFormInputs>({
resolver: yupResolver(schema),
});
const [filepath, setFilepath] = useState("vodeo.mp3");
const onSubmit: SubmitHandler<IFormInputs> = (data) => {
console.log('data submitted: ', data);
console.log('filepath: ', data.filepath);
};
return (
<ThemeProvider theme={theme}>
<Container component="main" maxWidth="lg">
<CssBaseline />
<Box
sx={{
marginTop: 8,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
>
<form onSubmit={handleSubmit(onSubmit)}>
<Box sx={{ mt: 3 }}>
<Grid container spacing={2}>
<Grid item xs={16} sm={6}>
<Controller
name="filepath"
control={control}
defaultValue=""
render={({ field }) => (
<TextField
{...field}
label="File Path"
error={!!errors.filepath}
helperText={errors.filepath ? errors.filepath?.message : ''}
autoComplete="file-path"
fullWidth
/>
)}
/>
</Grid>
<Button
type="submit"
variant="contained"
sx={{ mt: 3, mb: 2 }}
>
Submit
</Button>
</Grid>
</Box>
</form>
</Box>
</Container>
</ThemeProvider>
);
}
Update:
Here is the codeshare: https://codesandbox.io/s/boring-water-m47uxn?file=/src/App.tsx
When we change the text box value to auto, want to change the textbox value to audio.mp3. but its not working.
MUI Textfield have onChange too:
<TextField
error={Boolean(touched.name && errors.name)}
fullWidth
label={t('Name')}
name="name"
onBlur={handleBlur}
onChange={handleChange}
value={values.name}
variant="outlined"
autoComplete="off"
/>
'field' in render function contains onChange.
And state of form saved in useForm. In useForm props you have to add defaultValues. And you did not pass prop type="file", maybe its your problem.
Guide about create file input with react hook form: https://refine.dev/blog/how-to-multipart-file-upload-with-react-hook-form/
Textfield api: https://mui.com/material-ui/api/text-field/
s, I made a component "Checkbox" to be used in others forms of my app, but the state does not update after click. It works and get checked at the DOM, but the state doesn't change, it remains 'false'. I'm using Material-ui v.5.0 and React 18.0.1, all helps will be very appreciated. Thanks in advance. I don't know what mistake I'm doing. I'm a newbie in React. Below follows my codes. It should be a component, where I will use in another form. After checked, I want it to become disabled. Thanks folks.
// CardNotes Component
import React, {useState} from "react";
import Card from '#mui/material/Card';
import CardHeader from '#mui/material/CardHeader';
import CardContent from '#mui/material/CardContent';
import IconButton from '#mui/material/IconButton';
import { DeleteOutlined } from "#mui/icons-material";
import { Typography } from "#mui/material";
import { makeStyles } from "#mui/styles";
import Checkbox from './Checkbox';
import { Box } from '#mui/material';
const useStyles = makeStyles({
test: {
border: (note) => {
if (note.status == 'Urgente'){
return '1px solid red'
}
return '1px solid blue'
}
}
})
export default function CardNotes({ note, handleDelete }){
const [checked, setChecked] = useState(false);
console.log('checkbox', checked)
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setChecked(event.target.checked);
};
const classes = useStyles(note)
return( // receiving props from Notes
<div>
<Card elevation={3} className={classes.test}>
<CardHeader
titleTypographyProps={{
fontSize: 16,
}}
action={
<IconButton onClick={()=> handleDelete(note.id) }>
<DeleteOutlined />
</IconButton>
}
title={note.title}
subheader={note.status}
/>
<CardContent>
<Typography variant="display2" color="textSecondary">
{note.details}
</Typography>
</CardContent>
<Box ml={2}>
<Checkbox
label="Resolvido"
checked={checked}
onChange={ (e) => setChecked(e.target.checked)}>
</Checkbox>
</Box>
</Card>
</div>
)
}
// checkbox component
import React from 'react'
import {FormControl , FormControlLabel} from '#mui/material';
import Checkbox from '#mui/material/Checkbox';
export default function Chekbox (props) {
const { resolved, handleChange } = props;
return (
<FormControl>
<FormControlLabel
control={<Checkbox
checked={resolved}
color="primary"
onChange={handleChange}
/>}
label='Resolvido'
/>
</FormControl>
)
}
check names of props you pass to CheckBox Component.
there are differences between those and props you type in CheckBox file
I have a JS file (react) that looks like this:
import { Grid, TextField, makeStyles } from '#material-ui/core'
import React from 'react'
import {useState} from 'react'
//remove this function and refresh. see magic.
const useStyle = makeStyles(theme => ({
root:{
'& .MuiFormControl-root':{
width : '80%',
margin : theme.spacing(.75)
}
}
}))
const initialFormValues = {
id:0,
name:'',
username:'',
email:''
}
export default function EntryForm() {
const [values, setvalues] = useState(initialFormValues)
return (
<form className={useStyle().root}>
<Grid container>
<Grid item>
<TextField
size='small'
variant='outlined'
label='name'
value={values.name} />
<TextField
size='small'
variant='outlined'
label='username'
value={values.username} />
<TextField
size='small'
variant='outlined'
label='email'
value={values.email} />
</Grid>
<Grid item>
</Grid>
</Grid>
</form>
)
}
This works fine, and invoked, the fields get rendered along with it's parent components.
However, changing first line to:
import { Grid, TextField, makeStyles } from '#mui/material'
and refreshing the browser makes the whole page empty. Apparently, this happens specifically with makeStyles from '#mui/material' usage. Using Grid and Textfield from '#mui/material' only doesn't cause that.
What is happening here?
As per docs you should import makeStyles from #mui/styles.
Please try updating the import statement as:
import { makeStyles } from "#mui/styles";
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 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>
);
}