I can't write in the TextFields - reactjs

I am trying to add a new user to my database using the axios post method, with a form that I made with material ui, the application runs well does not mark me any console errors or in the browser and if it shows me the form but I can't write the TextFields.
Before adding the functions, I could write well but after adding Onchange and value I no longer let myself write
What could be happening?
Component
import React, { useState } from "react";
import axios from 'axios';
//useState hook create a state named user with initial state set to an object with name, lastname and age properties set to empty strings
function UserAdd(props) {
const initialState = { name: '', lastname: '', age:0 }
const [user, setUser] = useState(initialState)
function handleChange(event) {
setUser({...user, [event.target.name]: event.target.value})
}
function handleSubmit(event) {
event.preventDefault();
if(!user.name || !user.lastname || !user.age) return
async function postUser() {
try {
const response = await post('/api/addUser', user);
props.history.push(`/user/${response.data._id}`);
} catch(error) {
console.log('error', error);
}
}
postUser();
}
function handleCancel() {
props.history.push("/users");
}
return (
<div style={{ padding: 16, margin: 'auto', maxWidth: 1000 }}>
<Typography variant="h4" align="center" component="h1" gutterBottom>
Add User
</Typography>
<form onSubmit={handleSubmit} className={classes.container} >
<TextField
label="Name"
className={classes.textField}
value={user.name}
onChange={handleChange}
margin="normal"
variant="outlined"
/>
<TextField
id="filled-read-only-input"
label="Lastname "
className={classes.textField}
value={user.lastname}
onChange={handleChange}
margin="normal"
variant="outlined"
/>
<TextField
required
id="filled-required"
label="Age"
className={classes.textField}
value={user.age}
onChange={handleChange}
margin="normal"
variant="outlined"
/>
<Grid item style={{ marginTop: 30 }}>
<Button
variant="contained"
color="primary"
type="submit">
Add
</Button>
</Grid>
<Grid item style={{ marginTop: 30 }}>
<Button
onClick={handleCancel}
variant="contained"
type="cancel">
Cancel
</Button>
</Grid>
</form>
</div>
);
}
export default UserAdd;```

It looks like you need to have a name attribute to pass with event.target.name. Not sure what props TextField takes, but I assume it would be something like this:
<TextField
name="name" // Add this
label="Name"
className={classes.textField}
value={user.name}
onChange={handleChange}
margin="normal"
variant="outlined"
/>
Similarly, you'd need to have a name prop for the other input components.

Related

Formik form does not recognize Material ui Button

I am building a login form with Formik with Materail UI, but Formik doesn't recognize Button of Material UI. If I replace the Button with html button everything works. Could anybody explain why it's not working with the Button component. Below is my code:
import React, { ReactElement } from "react";
import TextField from "#material-ui/core/TextField";
import FormControl from "#material-ui/core/FormControl";
import { Formik, Form } from "formik";
import { makeStyles } from "#material-ui/core/styles";
import Button from "#material-ui/core/Button";
import Box from "#material-ui/core/Box";
const useStyles = makeStyles((theme) => ({
root: {
margin: theme.spacing(1),
width: 200,
display: "flex",
},
input: {
marginTop: 5,
marginBottom: 5,
},
}));
interface Props {}
export default function loginForm({}: Props): ReactElement {
const classes = useStyles();
return (
<Box className={classes.root}>
<Formik
initialValues={{ username: "", password: "" }}
validate={(values) => {
const errors: { username?: string; password?: string } = {};
if (!values.username) {
errors.username = "Required";
} else if (!values.password) {
errors.password = "Required";
}
return errors;
}}
onSubmit={(values, { setSubmitting }) => {
console.log("values: ", values);
setSubmitting(false);
}}
>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
isSubmitting,
}) => (
<form onSubmit={handleSubmit}>
<FormControl>
<TextField
className={classes.input}
error={errors.username ? true : false}
type="username"
name="username"
onChange={handleChange}
onBlur={handleBlur}
value={values.username}
label="Username"
variant="outlined"
helperText={
errors.username && touched.username && errors.username
}
/>
<TextField
className={classes.input}
error={errors.password ? true : false}
type="password"
name="password"
onChange={handleChange}
onBlur={handleBlur}
value={values.password}
label="Password"
variant="outlined"
helperText={
errors.password && touched.password && errors.password
}
/>
</FormControl>
<Box display="flex" justifyContent="space-between">
<Button
variant="contained"
color="primary"
disabled={isSubmitting}
>
Submit
</Button>
<Button
variant="contained"
color="secondary"
disabled={isSubmitting}
>
Cancel
</Button>
</Box>
</form>
)}
</Formik>
</Box>
);
}
please note the code above doesn't work, but if you replace Button with button, the form works.
In most browsers, a HTML button by default has the type=submit which means that Formik's submit handler will be called. A Material-UI button does not have this default so the submit handler will never be called. Try adding type=submit to your <Button> props.
(Also, check out Formik's Material-UI integration examples)
You should add the id to the form.
<form onSubmit={handleSubmit} id="myForm">
And bind the form id with submit button
<Button
type="submit"
form="myForm"
>

How to clear input fields after submit in react

so i'm creating my portfolio and i am now on the final page, the contact page. I have it almost finished. I have it hooked up with emailjs and i receive emails with the message inputted as expected.
The problem i'm having is, when the form is submitted, i don't know how to clear the UI input fields. I could disregard using e.preventDefault(), however, i would like to keep that, as i want to style the page if the desired result has been achieved(message sent), or if an error has occurred. I would like to mention that i had used state for the name, email and message beforehand, however, i was unable to use the state variables in conjunction with the emailjs syntax, more specifically, with the "e.target" section. When the form is submitted, the result is the message being sent to my email, with the text inputted by the user still in the input fields.
The code is below, with some names left as hidden for privacy reasons:
import React, { useState } from 'react'
import { Box, Grid, Typography, Button} from '#material-ui/core'
import Navbar from './Navbar';
import Styles, { InputField } from './Styles'
import SendIcon from '#material-ui/icons/Send'
import emailjs from 'emailjs-com'
function Contact() {
const classes = Styles()
function sendEmail(e) {
e.preventDefault()
emailjs.sendForm('gmail', 'hidden', e.target, 'hidden')
.then((result) => {
console.log(result.text);
result.text ==="OK" ? console.log("it worked") : console.log("didnt work")
}, (error) => {
console.log(error.text);
});
}
return (
<Box component='div'>
<Navbar/>
<Grid container justify='center'>
<Box component='form' className={classes.contactContainer} onSubmit={sendEmail}>
<Typography variant='h5' className={classes.contactHead}>Contact Me</Typography>
<InputField
id="name"
name="name"
fullWidth={true}
label="Name"
variant="outlined"
margin='dense'
size='medium'
/>
<br/>
<InputField
id="email"
name="email"
fullWidth={true}
label="Email"
variant="outlined"
margin='dense'
size='medium'
/>
<br/>
<InputField
id="message"
name="message"
fullWidth={true}
label="Enter Message Here"
multiline
rows={8}
variant="outlined"
margin='dense'
size='medium'
/>
<br/>
<Button
type="submit"
variant='outlined'
fullWidth={true}
endIcon={<SendIcon/>}
className={classes.contactButton}>
Contact Me
</Button>
</Box>
</Grid>
</Box>
)
}
export default Contact
For the simplest way to do it in your code, use useState to declare initial value of the fields such as:
const [name, setName] = useState("");
Then you need to set the "value" param in your InputField component, eg:
<InputField
id="name"
name="name"
fullWidth={true}
label="Name"
variant="outlined"
margin='dense'
size='medium'
value={name}
/>
And after receiving the result in emailjs.sendForm, use setName to reset the value of the name field, eg:
setName("")
Use the similar method for other fields.
Thank you for the answer, it helped, however did not fully fix the problem. That being said, i was able to find a solution. I used the onChange param and passed through a function which changes the state AND the value. Also, after receiving the result in emailjs.sendForm, i reset the value of all the fields.
const handleChange = (event) => {
event.target.name=="name"
? setName(event.target.value)
: event.target.name=="email"
? setEmail(event.target.value)
: event.target.name=="message"
? setMessage(event.target.value)
: console.log("error")
};
function sendEmail(e) {
e.preventDefault()
emailjs.sendForm('gmail', 'hiddenForPrivacy', e.target, 'hiddenForPrivacy')
.then((result) => {
console.log(result.text);
result.text ==="OK" ? console.log("it worked") : alert("didnt work")
setName("")
setMessage("")
setEmail("")
}, (error) => {
console.log(error.text);
});
}
The input fields now look like this:
return (
<Box component='div'>
<Navbar/>
<Grid container justify='center'>
<Box component='form' className={classes.contactContainer} onSubmit={sendEmail}>
<Typography variant='h5' className={classes.contactHead}>Contact Me</Typography>
<InputField
id="name"
name="name"
fullWidth={true}
label="Name"
variant="outlined"
margin='dense'
size='medium'
onChange={(e) => handleChange(e)}
value={name}
/>
<br/>
<InputField
id="email"
name="email"
fullWidth={true}
label="Email"
variant="outlined"
margin='dense'
size='medium'
onChange={(e) => handleChange(e)}
value={email}
/>
<br/>
<InputField
id="message"
name="message"
fullWidth={true}
label="Enter Message Here"
multiline
rows={8}
variant="outlined"
margin='dense'
size='medium'
onChange={(e) => handleChange(e)}
value={message}
/>
<br/>
<Button
type="submit"
variant='outlined'
fullWidth={true}
endIcon={<SendIcon/>}
className={classes.contactButton}>
Contact Me
</Button>
</Box>
</Grid>
</Box>

Why button's onClick event is triggered when i typing in TextField ReactJS

I have a sample code for Signing page as follows, When I am typing the username and passwords inside the text fields with every character the onClick event of the button is triggered and I can see the output of console.log(). Why it is triggered?
class Signin extends React.Component {
state = {
username: null,
password: null,
}
render () {
const { t, classes } = this.props;
return (
<div >
<div >
<div >
<Card>
<CardContent>
<form>
<TextField
inputProps={{ style:{fontSize:20, textAlign:'center', direction:'ltr'} }}
value={this.state.username}
onChange={e => this.setState({username: e.target.value})}
id="username"
label={t("Username")}
className={classes.textField}
fullWidth
margin="normal"
/>
<TextField
inputProps={{ style:{fontSize:20, textAlign:'center', direction:'ltr'} }}
value={this.state.password}
onChange={e => this.setState({password: e.target.value})}
id="password"
label={t("Password")}
className={classes.textField}
type="password"
fullWidth
margin="normal"
/>
<Button variant="raised" color="primary" fullWidth type="submit" onClick={console.log(this.state.username,this.state.password)} >{t("Login")}</Button>
</form>
</CardContent>
</Card>
</div>
</div>
</div>
);
}
}
Change your console.log from:
onClick={console.log(this.state.username,this.state.password)}
to like this below:
onClick={() => console.log(this.state.username,this.state.password)}
try this
it is happening because It depends on where exactly are you using the Arrow function. If the Arrow function is used in the render method, then they create a new instance every time render is called just like how bind would work.
<Button
variant="raised"
color="primary"
fullWidth type="submit"
onClick={()=>{console.log(this.state.username,this.state.password)} >{t("Login")}}</Button>

When you click on the button, the data is not added

I'm doing an app CRUD with React
I added a method POST data to REST API created in Node using Axios for add a New user and the form is made with Material UI.
With the method handleChange is handled OnChange event of the Form Input with Hooks style that set the state off the object.
The handleChange function in turn calls setUser which updates the user state with the new value.
But when filling the form and clicking on the Add button nothing happens, it does not throw an error but does not add the data,
Any idea why this happen?
import React, { useState } from "react";
import axios from 'axios';
function UserAdd(props) {
const initialState = { name: '', lastname: '', age:0 }
const [user, setUser] = useState(initialState)
function handleChange(event) {
setUser({...user, [event.target.name]: event.target.value})
}
function handleSubmit(event) {
event.preventDefault();
const data={name:user.name, lastname: user.lastname, age: user.age}
if(!user.name || !user.lastname || !user.age) return
async function postUser() {
try {
const response = await axios.post('/api/addUser', data);
props.history.push(`/user/${response.data._id}`);
} catch(error) {
console.log('error', error);
}
}
postUser();
}
function handleCancel() {
props.history.push("/users");
}
return (
<div style={{ padding: 16, margin: 'auto', maxWidth: 1000 }}>
<Typography variant="h4" align="center" component="h1" gutterBottom>
Add User
</Typography>
<form onSubmit={handleSubmit} className={classes.container} >
<TextField
name="name"
label="Name"
className={classes.textField}
value={user.name}
onChange={handleChange}
margin="normal"
variant="outlined"
/>
<TextField
name="lastname"
label="Lastname "
className={classes.textField}
value={user.lastname}
onChange={handleChange}
margin="normal"
variant="outlined"
/>
<TextField
name="age"
label="Age"
className={classes.textField}
value={user.age}
onChange={handleChange}
margin="normal"
variant="outlined"
/>
<Grid item style={{ marginTop: 30 }}>
<Button
variant="contained"
color="primary"
type="submit">
Add
</Button>
</Grid>
<Grid item style={{ marginTop: 30 }}>
<Button
onClick={handleCancel}
variant="contained"
type="cancel">
Cancel
</Button>
</Grid>
</form>
</div>
);
}
export default UserAdd
API Method
router.post('/api/addUser',async(req,res)=>{
try {
const {name,lastname, age}=req.body;
await pool.request()
.input('name', sql.VarChar(20), name)
.input('lastname', sql.VarChar(35), lastname)
.input('age', sql.Int (100), age)
.execute('AddUser')
res.send(req.body)
} catch (error) {
res.json({message:error.message})
}
});
I recreated you code snippet in codesandbox while omitting styles and not relevant elements.
https://codesandbox.io/s/wizardly-perlman-ydh20
but changed await post to alert. And form submitting is working. So the problem is most likely in post implementation.

How to get input value of TextField from Material UI without using onChange event?

I tried to use this.refs.myField.getValue() or this.refs.myTextField.input.value. But, they are depreciated.
I don't want to use onChange inside TextField, I just convert the text when clicking button Convert
import React from 'react';
import TextField from '#material-ui/core/TextField';
import Button from '#material-ui/core/Button';
class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
text: '',
};
};
handleConvertString = (event) => {
let str = this.refs.myField.getValue();
this.setState({
text: str.replace(/[dog]/gi, ''),
})
};
render() {
return (
<div>
<TextField
ref="myField"
fullWidth
/>
<Button variant="outlined" href="#outlined-buttons" onClick={this.handleConvertString}>
Convert
</Button>
<h1>{this.state.text}</h1>
</div>
)
}
}
export default Test;
Take a look at the MUI text field API docs.
You are trying to access the underlying value of the text area, so you need the ref of the HTML DOM element.
For the text area, use:
<TextField
inputRef={ref => { this.inputRef = ref; }}
fullWidth
/>
And then in your method access the value with this.inputRef.value.
const { register, handleSubmit } = useForm();
<form onSubmit={handleSubmit(formSubmit)}>
<label>
<TextField
id="outlined-basic"
label="email"
name="email"
fullWidth
variant="outlined"
inputRef={register}
required
/>
</label>
<br />
<label>
<br />
<TextField
id="outlined-secondary:cyan"
label="password"
name="password"
type="password"
fullWidth
variant="outlined"
inputRef={register}
required
/>
</label>
<br />
<br />
<Button
className={classes.root}
variant="contained"
color="primary"
fullWidth
type="submit"
>
Login
</Button>
</form>
Then handling it with :
const formSubmit = (data) => {
// Post Data
const postData = {
email: data.email,
pass: data.password,
};
console.log(data)

Resources