React, Material UI: Submit button not working on mobiles - reactjs

My react component Login controls user login functionality. I have a material UI submit button which posts the users credentials. It works fine, except on mobiles - when users are on their phones, the submit button doesn't work and the onClick event is not fired. Any suggestions on how to make it work?
Here's the login component:
import React from 'react'
import Header from './Header'
import TextField from "#material-ui/core/TextField";
import Button from '#material-ui/core/Button'
import {Link} from 'react-router-dom'
import firebase from 'firebase'
import {auth} from 'firebase/app'
class Login extends React.Component {
constructor() {
super();
this.state = {
email: "",
password: "",
errors:[]
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({
[e.target.name]: e.target.value,
});
}
handleSubmit(e) {
e.preventDefault()
const { email, password } = this.state
const { history } = this.props
const errorLog = []
auth().signInWithEmailAndPassword(email, password)
.then((res) => {
history.push('/gigregister')
console.log(`token: ${res.data.user.getIdToken()}`)
})
.catch((err) => {
if(err.code === 'auth/wrong-password'){
errorLog.push('Wrong credentials, please try again')
this.setState({
errors: errorLog
})
}
})
}
render() {
return (
<>
<div>
<Header />
</div>
<div className = 'login-container'>
<div className ='gig-button'>
<Link to="/Homepage" style={{ textDecoration: "none" }}>
<button className = 'gig-button-button'>Gigs this week</button>
</Link>
</div>
<div className="login-main">
<div className="login">
<h4>Venue login</h4>
<h5>Not registered? Sign up <Link to="/venueregister" style={{ textDecoration: "none" }}>here</Link></h5>
<form onSubmit={this.handleSubmit}>
<TextField
placeholder="Enter email"
id="email"
name="email"
onChange={this.handleChange}
/>
<TextField
placeholder="Enter password"
id="password"
name="password"
error ={this.state.errors ? true : false}
errorText = {this.state.errors}
helperText = {this.state.errors}
onChange={this.handleChange}
type ='password'
/>
<div className="button">
<Button type="submit">Submit</Button>
</div>
</form>
</div>
</div>
</div>
</>
);
}
}
export default Login;

You need to add cursor:'pointer' to your button's CSS rules. This allows the mobile devices recognise a button press and fire a click event instead.
You'll find more information in this GitHub issue here.
Hope this answer helps!

Related

Signup on reactjs using axios

so i was trying to make a signup & login features on my web. My problem here is i cant post signup data to my api.
Here is the code that i make :
import React, { Component } from 'react'
import { Container } from 'react-bootstrap'
import { API_URL } from '../utils/constant';
import axios from 'axios';
import swal from 'sweetalert';
export default class Signup extends Component {
constructor(props) {
super(props);
this.state = {
};
}
handleSubmit = e => {
e.preventDefault();
const data = {
username: this.username,
password: this.password,
};
axios
.post(API_URL + "signup", data)
.then(res => {
swal({
tittle: "sukses",
text: "sukses",
icon: "success",
button: false,
})
}
).catch(error => {
console.log(error);
}
)
};
render() {
return (
<div className="signup">
<Container>
<div className="signup-page">
<form onSubmit={this.handleSubmit}>
<div class="mb-3">
<label>Username</label>
<input type="text" name="username" placeholder="username anda" class="form-control" onChange={e=> this.username = e.target.value} />
<div class="form-text"></div>
</div>
<div class="mb-3">
<label>Password</label>
<input type="password" class="form-control" onChange={e=> this.password = e.target.value}/>
</div>
<button class="btn btn-primary">Sign Up</button>
</form>
</div>
</Container>
</div>
);
}
}
My code here is not giving me any error, but the data is not post/added to my API.
i hope there is any suggestion from anyone of you because im just new into this reactjs,
this is my github link so maybe you might check it :
https://github.com/dannyambarita/Tubes_PWL/

React Js Login Beginner

first of all I am a very beginner at React.js. I am creating my super simple static code which has to login the user by the credentials provided in the state and redirect to homepage. But for some reason it doesn't work and doesn't redirect me to the homepage, which has the route of '/', btw my Login route is '/login'. I would appreciate any help. Here is my code:
import React from 'react';
import TextField from '#material-ui/core/TextField';
import { makeStyles } from '#material-ui/core/styles';
import Typography from '#material-ui/core/Typography';
import Container from '#material-ui/core/Container';
import Button from '#material-ui/core/Button';
import HomePage from './HomePage';
import { Redirect } from 'react-router-dom';
class LoginPage extends React.Component {
constructor(props) {
super(props);
this.state = {
loginData: {
username: 'test',
password: 'test'
},
errors: {}
};
this.buttonClickHandle = this.buttonClickHandle.bind(this);
this.loginHandle = this.loginHandle.bind(this);
}
loginHandle(event) {
let field = event.target.name;
let value = event.target.value;
let loginData = this.state.loginData;
loginData[field] = value;
this.setState({loginData: loginData});
}
buttonClickHandle(event) {
event.preventDefault();
if ( this.state.loginData.username === this.target.username) {
console.log("User exists. Go to the login page");
return <Redirect to="/"/>
} else {
console.log("User doesn't exists. Show error message");
}
}
render() {
return (
<div className="loginPage">
<Container maxWidth="sm">
<h2>Login</h2>
<form noValidate autoComplete="off" onChange={this.loginHandle}>
<div className="loginForm">
<TextField
required
id="outlined-required"
label="E-mail"
variant="outlined"
placeholder="Your e-mail..."
className="loginInput"
/>
<TextField
required
id="outlined-password-input"
label="Password"
type="password"
autoComplete="current-password"
variant="outlined"
placeholder="Your password..."
className="loginInput"
/>
<Button
variant="contained"
color="primary"
onClick={this.buttonClickHandle}
>
Login
</Button>
</div>
</form>
</Container>
</div>
)
}
}
export default LoginPage
There are some things that look off in your code.
There is no onChange prop in forms only onSubmit
The button should trigger the onSubmit function, this is done by setting the type of the button as submit
To get the input values from the form you need to put a name and get them as event.target.name.value inside the onSubmit function
here is a working example of your code
class LoginPage extends React.Component {
constructor(props) {
super(props);
this.state = {
loginData: {
username: "test",
password: "test"
},
errors: {}
};
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(event) {
event.preventDefault();
if (
this.state.loginData.username === event.target.username.value &&
this.state.loginData.password === event.target.password.value
) {
console.log("User exists. Go to the login page");
return <Redirect to="/" />;
} else {
console.log("User doesn't exists. Show error message");
}
}
render() {
return (
<div className="loginPage">
<Container maxWidth="sm">
<h2>Login</h2>
<form noValidate autoComplete="off" onSubmit={this.handleSubmit}>
<div className="loginForm">
<TextField
required
name="username"
id="outlined-required"
label="E-mail"
variant="outlined"
placeholder="Your e-mail..."
className="loginInput"
/>
<TextField
required
name="password"
id="outlined-password-input"
label="Password"
type="password"
autoComplete="current-password"
variant="outlined"
placeholder="Your password..."
className="loginInput"
/>
<Button variant="contained" color="primary" type="submit">
Login
</Button>
</div>
</form>
</Container>
</div>
);
}
}
export default LoginPage;

Getting Data From React-Bootstrap Input

I am not finding good docs or videos on how to get data from my inputs with React-Bootstrap. I want to be able to click the button and then bring what I typed into the input box into my onClick function.
import React from "react";
import Button from 'react-bootstrap/Button';
import './Search.css';
import InputGroup from 'react-bootstrap/InputGroup';
import FormControl from 'react-bootstrap/FormControl';
class search extends React.Component {
constructor(props){
super(props);
this.text = React.createRef();
this.searchChar = this.searchChar.bind(this);
}
searchChar = () => {
console.log("Button Clicked")
const value = this.input.current.value;
console.log(value)
}
render() {
return (
<div className="searchBar">
<form>
<InputGroup className="mb-3">
<InputGroup.Prepend>
<InputGroup.Text id="basic-addon1">Character Search</InputGroup.Text>
</InputGroup.Prepend>
<FormControl ref = {this.input}
placeholder="Character Name"
aria-label="Character Name"
aria-describedby="basic-addon1"
/>
</InputGroup>
<Button onClick={this.searchChar(this.input)} variant="outline-danger">Search </Button>
</form>
</div>
);
}
}
export default search;
Just try to write your input values in state
for example;
import React from "react";
import Button from 'react-bootstrap/Button';
import './Search.css';
import InputGroup from 'react-bootstrap/InputGroup';
import FormControl from 'react-bootstrap/FormControl';
class search extends React.Component {
constructor(props){
super(props);
this.state = {
basicAddon1 : null,
};
}
searchChar = () => {
console.log("Button Clicked")
const value = this.state.basicAddon1;
console.log(value)
}
render() {
return (
<div className="searchBar">
<form>
<InputGroup className="mb-3">
<InputGroup.Prepend>
<InputGroup.Text id="basic-addon1">Character Search</InputGroup.Text>
</InputGroup.Prepend>
<FormControl
placeholder="Character Name"
aria-label="Character Name"
aria-describedby="basic-addon1"
onChange={event => {
this.setState({
basicAddon1 : event.target.value
});
}}
value={this.state.basicAddon1 ? this.state.basicAddon1 : ""}
/>
</InputGroup>
<Button onClick={this.searchChar(this.input)} variant="outline-danger">Search </Button>
</form>
</div>
);
}
}
export default search;
you can create inputChangeHandler function or something else for improve your code
it just basic
The same way you deal with getting data from a form in pure React, you do with react-bootstrap. This answer here shows many options to do so.
My favourite approach among those options is this one. Using that approach your code would be something like:
class search extends React.Component {
constructor(props) {
super(props)
this.handleSave = this.handleSave.bind(this)
}
onChange(event) {
// Intended to run on the change of every form element
event.preventDefault()
this.setState({
[event.target.name]: event.target.value,
})
}
handleSave() {
console.log(`Do something with : {this.state.characterName}`)
}
render() {
return (
<div className="searchBar">
<form>
<InputGroup className="mb-3">
<InputGroup.Prepend>
<InputGroup.Text id="basic-addon1">
Character Search
</InputGroup.Text>
</InputGroup.Prepend>
<FormControl
name="characterName"
placeholder="Character Name"
aria-label="Character Name"
aria-describedby="basic-addon1"
onChange={this.onChange.bind(this)}
/>
</InputGroup>
<Button onClick={this.handleSave} variant="outline-danger">
Search{' '}
</Button>
</form>
</div>
)
}
}

Where to put proptypes validation?

Im my react application, Im in the refactoring phase. I want to separate redux part from the components. Im confused about where to put proptypes validation? Should the redux props be validated in the container file, and component props should be validated on the component? Or should the both prop types be handled on the component? Or in container? Here is my code.
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import PropTypes from 'prop-types';
import {bindActionCreators} from 'redux';
import { connect } from 'react-redux';
import { registerUser } from '../../../actions';
import { TextFieldGroup } from '../../../components/UI';
class RegisterScreen extends Component {
state = {
name: '',
email: '',
password: '',
password2: '',
errors: {}
};
componentDidMount() {
if (this.props.auth.isAuthenticated) {
this.props.history.push('./dashboard');
}
}
componentWillReceiveProps(nextProps) {
if (nextProps.errors) {
this.setState({ errors: nextProps.errors });
}
}
onChange = e => {
this.setState({
[e.target.name]: e.target.value
});
}
onSubmit = e => {
e.preventDefault();
const newUser = {
name: this.state.name,
email: this.state.email,
password: this.state.password,
password2: this.state.password2
}
this.props.registerUser(newUser, this.props.history);
}
render() {
const { errors } = this.state;
return (
<div className='register'>
<div className='container'>
<div className='row'>
<div className='col-md-8 m-auto'>
<h1 className='display-4 text-center'>Sign Up</h1>
<p className='lead text-center'>
Create Your Developer Connector Account
</p>
<form noValidate onSubmit={this.onSubmit}>
<TextFieldGroup
className={errors.email}
placeholder="* Full Name"
name="name"
value={this.state.name}
onChange={this.onChange}
error={errors.name}
/>
<TextFieldGroup
type='email'
className={errors.email}
placeholder="* Email Address"
name="email"
value={this.state.email}
onChange={this.onChange}
error={errors.email}
info='This site uses Gravatar so if you want a profile image, use a Gravatar email'
/>
<TextFieldGroup
type='password'
className={errors.password}
placeholder="* Password"
name="password"
value={this.state.password}
onChange={this.onChange}
error={errors.password}
/>
<TextFieldGroup
type='password'
className={errors.password2}
placeholder="* Confirm Password"
name="password2"
value={this.state.password2}
onChange={this.onChange}
error={errors.password2}
/>
<input type='submit' className='btn btn-info btn-block mt-4' />
</form>
</div>
</div>
</div>
</div>
);
}
}
RegisterScreen.propTypes = {
registerUser: PropTypes.func.isRequired,
auth: PropTypes.object.isRequired,
errors: PropTypes.object.isRequired
}
const mapStateToProps = state => ({
auth: state.auth,
errors: state.errors
});
const mapDispatchToProps = dispatch => ({
registerUser: bindActionCreators(registerUser, dispatch)
});
export default connect(mapStateToProps, mapDispatchToProps)(withRouter(RegisterScreen));
You should define the PropTypes in the component as you have in the example there. When deciding when to use PropTypes for static typing, you should always guard against incoming props that can directly affect the desired result of the component when rendered. By that I mean, if the component requires "auth" or "errors" props, then you should define the PropTypes for the component receiving those properties, whether through HoC in this case redux or any other mode of passing data down.

redux-form v6: Form submission canceled because the form is not connected

I am getting this error in my console.
"Form submission canceled because the form is not connected"
after trying to migrate my redux-form from v5 to v6 since we migrated our app to a more recent version of React.
I am not sure what is going wrong here so i figured I could use a second or third pair of eyes.
Here is my "Smart Component"
import React, { PropTypes } from 'react';
import { reduxForm } from 'redux-form/immutable';
import { connect } from 'react-redux';
import { logUserIn } from '../../actions/authentication';
import { VALID_EMAIL_REGEX } from '../../config/app_config';
import LoginForm from './LoginForm';
const FORM_ID = 'loginForm';
export class LoginFormContainer extends React.Component {
static propTypes = {
handleSubmit: PropTypes.func.isRequired,
submitting: PropTypes.bool.isRequired,
loginAction: PropTypes.func.isRequired,
};
performLogin = (params) => {
const { loginAction } = this.props;
const credentials = {
email: params.email,
password: params.password,
};
loginAction(credentials, '/home');
}
render() {
const { handleSubmit, submitting } = this.props;
return (
<LoginForm
handleSubmit={ handleSubmit }
loginFunction={ this.performLogin }
submitting={ submitting }
/>
);
}
}
const validate = values => {
const errors = {};
if (!values.email || values.email === '') {
errors.email = 'Required';
}
else if (!VALID_EMAIL_REGEX.test(values.email)) {
errors.email = 'Invalid email address';
}
if (!values.password || values.password === '') {
errors.password = 'Required';
}
return errors;
};
LoginFormContainer = reduxForm({
form: FORM_ID,
validate,
})(LoginFormContainer);
export default connect(null, {
loginAction: logUserIn,
})(LoginFormContainer);
I am passing down my submission handler function as a prop to my actual form that contains the Field component for inputs. The loginAction will link to the action for redux to send the values to the backend and redirect to home.
import React, { PropTypes } from 'react';
import { Field } from 'redux-form/immutable';
import { getClassName, checkButtonDisabled } from '../../utils/forms';
import { Link } from 'react-router';
const renderInput = (field) => {
return (
<div className={ getClassName(field.meta.touched, field.meta.error) }>
<input
{...field.input}
className="form-control form-control-success"
type={field.type}
/>
{field.meta.touched &&
field.meta.error &&
<span className="error">{field.meta.error}</span>}
</div>
);
};
export default class LoginForm extends React.Component {
static propTypes = {
handleSubmit: PropTypes.func.isRequired,
loginFunction: PropTypes.func.isRequired,
submitting: PropTypes.bool.isRequired,
};
render() {
const {
loginFunction,
submitting } = this.props;
return (
<form onSubmit={ loginFunction.bind(this) }>
<fieldset>
<div>
<label className="form-control-label">
Email address
</label>
<Field
name="email"
component={renderInput}
type="text"
placeholder="example#exampledomain.com"
/>
</div>
<div>
<label className="form-control-label">
Password
</label>
<Field
name="password"
component={renderInput}
type="password"
placeholder="your password"
/>
</div>
</fieldset>
<button
type="submit"
className="btn btn-primary"
disabled={ checkButtonDisabled(submitting) }
>
Log In
</button>
<Link to="/forgot-password">Forgot Password?</Link>
</form>
);
}
}
I successfully was able to get the form to work but when I hit login I get the error above and I am redirected to home, but I am not authenticated and I get a 422 error as well. I couldn't tell if my form connecting is the only error or if my action is not getting the right information from the form submission function.
Got any suggestions?
You are redirected home, because your loginFunction() is fired, but the form is not submitted
There are a couple of things that need to be updated. Your <form> tag must have a corresponding id and it should handle submit by passing your function to redux-form inbuilt submit handler. So you modifying LoginForm class as follows should get the form working
<form id="loginForm" onSubmit={ handleSubmit(this.loginFunction.bind(this)) } >
More about internal redux-form method handleSubmit here: http://redux-form.com/6.5.0/docs/api/Form.md/
Using the answer given to me above I just wanted to clarify what I did to solve the issue.
I grabbed the handleSubmit method that comes from the reduxForm and passed it to the LoginForm as a prop from the container that also retrieved it from the props.
I also imported the Form component from redux-form on the LoginForm component and just simply replaced the normal JSX tag with .
here were the final changes I made.
LoginForm.jsx:
//Added Form from redux-form
import { Field, Form } from 'redux-form/immutable';
render() {
const {
handleSubmit,//defined handleSubmit function from props which comes from the reduxForm being exported to the state.
loginFunction,
submitting } = this.props;
return (
//replaced <form></form> with <Form></Form>
<Form id="loginForm" onSubmit={ handleSubmit(loginFunction.bind(this)) }>
//passed my loginFunction into the handleSubmit function
//added an id to <Form> that corresponds to the forms id that was passed in reduxForm({ form: 'loginForm' })
<fieldset>
<div>
<label className="form-control-label">
Email address
</label>
<Field
name="email"
component={renderInput}
type="text"
placeholder="example#exampledomain.com"
/>
</div>
<div>
<label className="form-control-label">
Password
</label>
<Field
name="password"
component={renderInput}
type="password"
placeholder="your password"
/>
</div>
</fieldset>
<button
type="submit"
className="btn btn-primary"
disabled={ checkButtonDisabled(submitting) }
>
Log In
</button>
<Link to="/forgot-password">Forgot Password?</Link>
</Form>
);

Resources