I am pretty new to React, and I am making my first app using material-ui, and I have managed to render the components I intend, but I haven't been able to print them stacked, they show in line:
I have tried to wrap them with div and p, and I get the same result.
This is the code of my component:
import React, { Component } from 'react';
import Button from '#material-ui/core/Button';
import classNames from 'classnames';
import PropTypes from 'prop-types';
import { withStyles } from '#material-ui/core/styles';
import Input from '#material-ui/core/Input';
import InputLabel from '#material-ui/core/InputLabel';
import InputAdornment from '#material-ui/core/InputAdornment';
import FormControl from '#material-ui/core/FormControl';
import Visibility from '#material-ui/icons/Visibility';
import VisibilityOff from '#material-ui/icons/VisibilityOff';
import IconButton from '#material-ui/core/IconButton';
const styles = theme => ({
root: {
display: 'flex',
flexWrap: 'wrap',
},
margin: {
margin: theme.spacing.unit,
},
withoutLabel: {
marginTop: theme.spacing.unit * 3,
},
textField: {
flexBasis: 200,
},
button: {
margin: theme.spacing.unit,
},
input: {
display: 'none',
},
});
class LoginModal extends Component {
state = {
password: '',
showPassword: false,
};
render() {
const { classes } = this.props
return (
<div className={classes.root}>
<h1>Welcome to My App...</h1>
<FormControl className={classNames(classes.margin, classes.textField)}>
<InputLabel htmlFor="adornment-email">eMail</InputLabel>
<Input i
d="adornment-email"
variant="filled"
/>
</FormControl>
<FormControl className={classNames(classes.margin, classes.textField)}>
<InputLabel htmlFor="adornment-password">Password</InputLabel>
<Input
id="adornment-password"
variant="filled"
type={this.state.showPassword ? 'text' : 'password'}
value={this.state.password}
endAdornment={
<InputAdornment position="end">
<IconButton
aria-label="Toggle password visibility"
onClick={this.handleClickShowPassword}
>
{this.state.showPassword ? <Visibility /> : <VisibilityOff />}
</IconButton>
</InputAdornment>
}
/>
<p>Did you forget your password?</p>
<Button color="primary" variant="contained">Login</Button>
</FormControl>
</div>
);
};
}
LoginModal.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(LoginModal);
Only the two latest components show stacked, but the rest show in line.
How can I instruct React to display components in an stacked fashion?
update your root style to:
root: {
display: 'flex',
flex-direction: column;
},
you may need to adjust other flex properties to get the alignment you want.
I found that Material-UI uses Grid components to manage responsiveness, and you can use it to arrange objects in display.
This is how I used Grid to display my objects the way I wanted:
class LoginModal extends Component {
state = {
password: '',
showPassword: false,
};
render() {
const { classes } = this.props
return (
<div className={classes.root}>
<Grid container spacing={24}>
<Grid item xs={12}>
<h1>Welcome to My App...</h1>
</Grid>
<Grid item xs={12}>
<FormControl className={classNames(classes.margin, classes.textField)}>
<InputLabel htmlFor="adornment-email">eMail</InputLabel>
<Input
id="adornment-email"
variant="filled"
/>
</FormControl>
</Grid>
<Grid item xs={12}>
<FormControl className={classNames(classes.margin, classes.textField)}>
<InputLabel htmlFor="adornment-password">Password</InputLabel>
<Input
id="adornment-password"
variant="filled"
type={this.state.showPassword ? 'text' : 'password'}
value={this.state.password}
endAdornment={
<InputAdornment position="end">
<IconButton
aria-label="Toggle password visibility"
onClick={this.handleClickShowPassword}
>
{this.state.showPassword ? <Visibility /> : <VisibilityOff />}
</IconButton>
</InputAdornment>
}
/>
<p>Did you forget your password?</p>
<Button color="primary" variant="contained">Login</Button>
</FormControl>
</Grid>
</Grid>
</div>
);
};
}
And this is the result:
Related
I am using react with formik and typescript in my project. I am using withFormik HOC in my forms, code is below
import React from "react";
//Libraries import........
import {
Container,
Box,
Link,
Grid,
Checkbox,
FormControlLabel,
TextField,
CssBaseline,
Avatar,
Typography,
makeStyles,
Theme,
} from "#material-ui/core";
import LockOutlinedIcon from "#material-ui/icons/LockOutlined";
import { Form, FormikProps, FormikValues, useFormik, withFormik } from "formik";
import * as Yup from "yup";
//Components import........
import { Button } from "#components/button";
//Interfaces ..........
interface FormValues {
email?:string,
password?:string
}
interface IProps extends FormikProps<FormValues> {
// onSubmit(e:React.FormEvent<HTMLInputElement>):void
}
const useStyles = makeStyles((theme: Theme) => ({
paper: {
marginTop: theme.spacing(8),
display: "flex",
flexDirection: "column",
alignItems: "center",
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main,
},
form: {
width: "100%", // Fix IE 11 issue.
marginTop: theme.spacing(1),
},
submit: {
margin: theme.spacing(3, 0, 2),
},
}));
const Login: React.FC<IProps> = (props) => {
const classes = useStyles();
const { handleSubmit, handleBlur, handleChange, handleReset, errors } = props;
console.log(errors);
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign in
</Typography>
<form className={classes.form} noValidate>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
id="email"
label="Email Address"
name="email"
autoFocus
/>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
/>
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Sign In
</Button>
<Grid container>
<Grid item xs>
<Link href="#" variant="body2">
Forgot password?
</Link>
</Grid>
<Grid item>
<Link href="#" variant="body2">
{"Don't have an account? Sign Up"}
</Link>
</Grid>
</Grid>
</form>
</div>
<Box mt={8}></Box>
</Container>
);
};
export const LoginView = withFormik<IProps, FormValues>({
enableReinitialize: true,
mapPropsToValues: (props) => {
console.log(props);
return { email: "", password: "" };
},
validationSchema: Yup.object({
// email: Yup.string().required(),
}),
handleSubmit: (values) => {
console.log(values);
},
})(Login);
and then when in my project i import and use LoginView inside my pages like
import React from "react";
import { LoginView } from "#components/user/login";
const Home: React.FC = (props: any) => {
return (
<div
style={{ display: "flex", flexDirection: "column", minHeight: "100vh" }}
>
<LoginView />
</div>
);
};
export default Home;
i get an error where i write
Type '{}' is not assignable to type 'IProps'. Type '{}' is missing
the following properties from type 'FormikState': values,
errors, touched, isSubmitting, and 2 more.
First Generic Type provided to withFormik shouldn't extend from FormikValues.
Define IProps like this
interface IProps {
// onSubmit(e:React.FormEvent<HTMLInputElement>):void
}
See this https://codesandbox.io/s/stackoverflow-69143042-wlvz9
I'm currently working on a register form using react, and using axios to connect with my Django Rest Framework API, but I got some issue with from validation, I look up many solutions but many of them use React class component, and those using react function component don't work with axios.
I could really use your help on any type of form validation that i could use, this is my current code
import React, { useState } from 'react';
import axiosInstance from '../../../network/axios';
// eslint-disable-next-line
import { useHistory } from 'react-router-dom';
import { Link } from 'react-router-dom';
//Material-Ui
import Avatar from '#material-ui/core/Avatar';
import Button from '#material-ui/core/Button';
import CssBaseline from '#material-ui/core/CssBaseline';
import TextField from '#material-ui/core/TextField';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import Checkbox from '#material-ui/core/Checkbox';
import Grid from '#material-ui/core/Grid';
import Box from '#material-ui/core/Box';
import LockOutlinedIcon from '#material-ui/icons/LockOutlined';
import Typography from '#material-ui/core/Typography';
import { makeStyles } from '#material-ui/core/styles';
import Container from '#material-ui/core/Container';
function Copyright() {
return (
<Typography variant="body2" color="textSecondary" align="center">
{'Copyright © '}
<Link color="inherit" href="https://material-ui.com/">
Your Website
</Link>{' '}
{new Date().getFullYear()}
{'.'}
</Typography>
);
}
const useStyles = makeStyles((theme) => ({
paper: {
marginTop: theme.spacing(8),
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
},
avatar: {
margin: theme.spacing(1),
// backgroundColor: theme.palette.secondary.main,
backgroundColor: 'linear-gradient(62deg, #bbbbbb 0%, #6b6868 100%)',
},
form: {
width: '100%', // Fix IE 11 issue.
marginTop: theme.spacing(3),
},
submit: {
margin: theme.spacing(3, 0, 2),
// background: 'linear-gradient(62deg, #bbbbbb 0%, #6b6868 100%)',
background:'linear-gradient(90deg, rgba(9,42,121,1) 0%, rgba(11,161,163,1) 35%, rgba(0,212,255,1) 80%)',
// background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
borderRadius: 3,
border: 0,
color: 'white',
height: 48,
padding: '0 30px',
boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)',
},
}));
export default function SignUp() {
//histoary to make a redirect to
// eslint-disable-next-line
const history = useHistory();
const initialFormData = Object.freeze({
email: '',
first_name: '',
last_name: '',
password1: '' ,
password2: '' ,
});
const [formData, updateFormData] = useState(initialFormData);
const handleChange = (e) => {
updateFormData({
...formData,
// Trimming any whitespace
[e.target.name]: e.target.value.trim(),
});
};
const handleSubmit = (e) => {
e.preventDefault();
console.log(formData);
axiosInstance
.post(`users/create/`, {
email: formData.email,
first_name: formData.first_name ,
last_name: formData.last_name ,
password1: formData.password1 ,
password2: formData.password2 ,
})
.then((res) => {
history.push('/welcome');
console.log(res);
console.log(res.data);
});
}
const classes = useStyles();
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign up
</Typography>
<form className={classes.form} noValidate>
<Grid container spacing={2}>
<Grid item xs={12} sm={6}>
<TextField
autoComplete="fname"
name="first_name"
variant="outlined"
required
fullWidth
id="first_name"
label="First Name"
autoFocus
onChange={handleChange}
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
variant="outlined"
required
fullWidth
id="last_name"
label="Last Name"
name="last_name"
autoComplete="lname"
onChange={handleChange}
/>
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
id="email"
label="Email Address"
name="email"
autoComplete="email"
onChange={handleChange}
/>
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
name="password1"
label="Password"
type="password"
id="password1"
autoComplete="current-password1"
onChange={handleChange}
/>
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
name="password2"
label="Password"
type="password"
id="password2"
autoComplete="current-password2"
onChange={handleChange}
/>
</Grid>
<Grid item xs={12}>
<FormControlLabel
control={<Checkbox value="allowExtraEmails" color="primary" />}
label="I want to receive inspiration, marketing promotions and updates via email."
/>
</Grid>
</Grid>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
onClick= {handleSubmit}
>
Sign Up
</Button>
</form>
<Grid container justify="flex-end">
<Grid item>
<Button hcomponent={Link} to="/logins" variant="body2">
Already have an account? Sign in
</Button>
</Grid>
</Grid>
</div>
<Box mt={5}>
<Copyright />
</Box>
</Container>
);
}
Sorry for the question, maybe it is very silly but I am learning and I have not been able to solve it, I took the signup template from material-ui and decided to perform the validations with react hook forms and everything works but I wanted to add the function of showing or hiding the password with it eye icon, it turns out that when I manage to do it, it is changing the field type from "text-field" to "FormControl" but they no longer show me the help messages when there is an error.
In the code there are 2 password fields, the first works as I want but without the hide / unhide and the second has the icon but as I mentioned it does not show the message.
Something that strikes me is that it turns red correctly when there is an error.
I would appreciate if you could help me make it work properly. Thank you
import React, {useState} from 'react';
import Avatar from '#material-ui/core/Avatar';
import Button from '#material-ui/core/Button';
import CssBaseline from '#material-ui/core/CssBaseline';
import TextField from '#material-ui/core/TextField';
import Link from '#material-ui/core/Link';
import Grid from '#material-ui/core/Grid';
import Box from '#material-ui/core/Box';
import LockOutlinedIcon from '#material-ui/icons/LockOutlined';
import Typography from '#material-ui/core/Typography';
import { makeStyles } from '#material-ui/core/styles';
import Container from '#material-ui/core/Container';
import Visibility from '#material-ui/icons/Visibility';
import VisibilityOff from '#material-ui/icons/VisibilityOff';
import InputAdornment from '#material-ui/core/InputAdornment';
import IconButton from '#material-ui/core/IconButton';
import FormControl from '#material-ui/core/FormControl';
import clsx from 'clsx';
import InputLabel from '#material-ui/core/InputLabel';
import * as yup from 'yup'
import { yupResolver } from '#hookform/resolvers';
import { useForm} from "react-hook-form";
import { OutlinedInput } from '#material-ui/core';
function Copyright() {
return (
<Typography variant="body2" color="textSecondary" align="center">
{'Copyright © '}
<Link color="inherit" href="https://material-ui.com/">
Your Website
</Link>{' '}
{new Date().getFullYear()}
{'.'}
</Typography>
);
}
const useStyles = makeStyles((theme) => ({
paper: {
marginTop: theme.spacing(8),
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main,
},
margin: {
margin: theme.spacing(1),
},
form: {
width: '100%', // Fix IE 11 issue.
marginTop: theme.spacing(3),
},
submit: {
margin: theme.spacing(3, 0, 2),
},
}));
const RegisterSchema = yup.object().shape({
password: yup
.string()
.trim()
.required('Requerido.')
.min(8, 'Contraseña es muy corta - Debe contener al menos 8 caracteres.')
.max(15, 'Contraseña es muy larga - Debe contener máximo 15 caracteres.')
.matches(/[a-zA-Z]/, 'Contraseña solo puede contener letras latinas.')
});
export default function SignUp() {
const classes = useStyles();
const [data, setData] = useState({
password:'',
showPassword: false,
});
const handleChange = (prop) => (event) => {
setData({ ...data, [prop]: event.target.value });
};
const handleClickShowPassword = () => {
setData({ ...data, showPassword: !data.showPassword });
};
const handleMouseDownPassword = (event) => {
event.preventDefault();
};
const handleInputChange = (e) => {
console.log(e.target.value);
setData ({
...data,
fullName: (data.firstName + ' ' + data.lastName),
[e.target.name] : e.target.value,
})
}
const {register, handleSubmit, errors} = useForm({
resolver: yupResolver(RegisterSchema),
});
const onSubmit = (data) => {
console.log(data);
};
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Registro
</Typography>
<form className={classes.form} noValidate onSubmit={handleSubmit(onSubmit)}>
<Grid container spacing={2}>
{<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
name="password"
label="Contraseña"
type="password"
id="password"
autoComplete="current-password"
onChange={handleInputChange}
inputRef={register}
error ={!!errors.password}
helperText={errors.password ? errors.password.message : ''}
endAdornment={
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={handleClickShowPassword}
onMouseDown={handleMouseDownPassword}
edge="end"
>
{data.showPassword ? <Visibility /> : <VisibilityOff />}
</IconButton>
</InputAdornment>
}
/>
</Grid>}
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
autoComplete="current-password"
inputRef={register}
error ={!!errors.password}
helperText={errors.password ? errors.password.message : ''}
name="password"
type="password"
id="password"
fullWidth
required
>
<InputLabel
htmlFor="outlined-adornment-password">
Contraseña
</InputLabel>
<OutlinedInput
id="outlined-adornment-password"
type={data.showPassword ? 'text' : 'password'}
value={data.password}
onChange={handleChange('password')}
endAdornment={
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={handleClickShowPassword}
onMouseDown={handleMouseDownPassword}
edge="end"
>
{data.showPassword ? <Visibility /> : <VisibilityOff />}
</IconButton>
</InputAdornment>
}
labelWidth={92}
/>
</FormControl>
</Grid>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Registrate
</Button>
<Grid container justify="flex-end">
<Grid item>
<Link href="#" variant="body2">
¿Tienes una cuenta? Ingresa
</Link>
</Grid>
</Grid>
</form>
</div>
<Box mt={5}>
<Copyright />
</Box>
</Container>
);
}
In your password Text Field component
you may use this solution , try adding some state to your component that defines whether the user want to show or hide the password and name it for example "showPassword"
const [showPassword,setShow] = useState(false)
<TextField
variant="outlined"
required
fullWidth
name="password"
label="Contraseña"
type={showPassword?"text":"password"}
/>
call setShow(!showPassword) when ever the user click on eye button
Now when ever setShow changes to " true " , the type of the input will be text and thus the password will be shown
Try this. It's worked for me.
<TextField
label='Password'
fullWidth
required
type={showPassword ? 'text' : 'password'}
error={!!errors['password']}
helperText={errors['password'] ? errors['password'].message : ''}
{...register('password')}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={handleClickShowPassword}
onMouseDown={handleMouseDownPassword}
edge="end"
>
{showPassword ? <Visibility /> : <VisibilityOff />}
</IconButton>
</InputAdornment>
)
}}
/>
Question from React newbie!
I have Material UI React login form and am trying to use hook within login form. But getting invalid hook call error. No luck so far. Help please.. loginformstyles.js is the hook I am trying to use in the signin.js file.. The login page has two text fields - username and password and a Submit button.
import React from 'react';
import Avatar from '#material-ui/core/Avatar';
import Button from '#material-ui/core/Button';
import CssBaseline from '#material-ui/core/CssBaseline';
import TextField from '#material-ui/core/TextField';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import Checkbox from '#material-ui/core/Checkbox';
import Link from '#material-ui/core/Link';
import Grid from '#material-ui/core/Grid';
import Box from '#material-ui/core/Box';
import LockOutlinedIcon from '#material-ui/icons/LockOutlined';
import Typography from '#material-ui/core/Typography';
import Container from '#material-ui/core/Container';
import { ValidatorForm, TextValidator} from 'react-material-ui-form-validator';
import { useStyles } from './loginformstyles';
export default class MyForm extends React.Component {
Copyright() {
return (
<Typography variant="body2" color="textSecondary" align="center">
{'Copyright © '}
<Link color="inherit" href="https://material-ui.com/">
Task Manager
</Link>{' '}
{new Date().getFullYear()}
{'.'}
</Typography>
);
}
handleChange (event) {
const email = event.target.value;
this.setState({ email });
}
render() {
const classes = useStyles();
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign in
</Typography>
<form className={classes.form} >
<TextField
variant="outlined"
margin="normal"
required
fullWidth
id="email"
label="Email Address"
name="email"
autoComplete="email"
autoFocus
validators={['required', 'isEmail']}
errorMessages={['this field is required', 'email is not valid']}
onChange={this.handleChange}
/>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
/>
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Sign In
</Button>
<Grid container>
<Grid item xs>
<Link href="#" variant="body2">
Forgot password?
</Link>
</Grid>
<Grid item>
<Link href="#" variant="body2">
{"Don't have an account? Sign Up"}
</Link>
</Grid>
</Grid>
</form>
</div>
<Box mt={8}>
<this.Copyright />
</Box>
</Container>
);
}
}
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
export const useStyles = makeStyles((theme) => ({
paper: {
marginTop: theme.spacing(8),
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main,
},
form: {
width: '100%', // Fix IE 11 issue.
marginTop: theme.spacing(1),
},
submit: {
margin: theme.spacing(3, 0, 2),
},
}));
If you just want to make this work, you could wrap the it and then expose the styles into child component, ex.
const Wrapper = ({ children }) => {
const classes = useStyles()
return children(classes)
}
and then you can do
<Wrapper>
{classes => <Copyright classes={classes} />}
</Wrapper>
Of course, this is just to get it working. In general you shouldn't mix class and hook, but as long as you can turn them into components, then you can mix and match.
I've created a SignIn component using Material UI's example.
import React from 'react';
import PropTypes from 'prop-types';
import Avatar from '#material-ui/core/Avatar';
import Button from '#material-ui/core/Button';
import CssBaseline from '#material-ui/core/CssBaseline';
import FormControl from '#material-ui/core/FormControl';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import Checkbox from '#material-ui/core/Checkbox';
import Input from '#material-ui/core/Input';
import InputLabel from '#material-ui/core/InputLabel';
import LockOutlinedIcon from '#material-ui/icons/LockOutlined';
import Paper from '#material-ui/core/Paper';
import Typography from '#material-ui/core/Typography';
import withStyles from '#material-ui/core/styles/withStyles';
const styles = theme => ({
main: {
width: 'auto',
display: 'block', // Fix IE 11 issue.
marginLeft: theme.spacing.unit * 3,
marginRight: theme.spacing.unit * 3,
[theme.breakpoints.up(400 + theme.spacing.unit * 3 * 2)]: {
width: 400,
marginLeft: 'auto',
marginRight: 'auto',
},
},
paper: {
marginTop: theme.spacing.unit * 8,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: `${theme.spacing.unit * 2}px ${theme.spacing.unit * 3}px ${theme.spacing.unit * 3}px`,
},
avatar: {
margin: theme.spacing.unit,
backgroundColor: theme.palette.secondary.main,
},
form: {
width: '100%', // Fix IE 11 issue.
marginTop: theme.spacing.unit,
},
submit: {
marginTop: theme.spacing.unit * 3,
},
});
function SignIn(props) {
const { classes } = props;
return (
<main className={classes.main}>
<CssBaseline />
<Paper className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign in
</Typography>
<form className={classes.form}>
<FormControl margin="normal" required fullWidth>
<InputLabel htmlFor="email">Email Address</InputLabel>
<Input id="email" name="email" autoComplete="email" autoFocus />
</FormControl>
<FormControl margin="normal" required fullWidth>
<InputLabel htmlFor="password">Password</InputLabel>
<Input name="password" type="password" id="password" autoComplete="current-password" />
</FormControl>
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Sign in
</Button>
</form>
</Paper>
</main>
);
}
SignIn.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(SignIn);
Now I want to use it in a parent component with a submit handler. But I can't figure out how to execute the handler when the form in the child component is submitted
import React, { Component } from "react";
import SignIn from "../components/SignIn";
export default class Login extends Component {
constructor(props) {
super(props);
this.state = {
};
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit = async event => {
// Do Stuff
}
render() {
return (
<div className="Login">
<SignIn onSubmit={this.handleSubmit}/>
</div>
);
}
}
Change your button in the SignIn component to call the submit handler passed in through the props like so:
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
onClick={this.props.onSubmit}
>
Sign in
</Button>