React form w/ custom validation submit to PHP - reactjs

How can I add basic validation to this form in React in which prevents default submit. I have found many examples but none that help me to implement the validation to my existing code.
``import React from "react";
export default function App() {
return (
<form method="POST" action="/example.php">
<input name="Username" required type="text" />
<input required name="Password" type="Password" />
<button type="submit" className="btn-login" />
</form>
);
}``

First you need to handle onSubmit and call event.preventDefault()— this is to prevent the default submit:
export default function App() {
handleSubmit = event => {
event.preventDefault();
}
return (
<form onSubmit={ handleSubmit }>
...
</form>
);
}
After that, you can use the Constraint Validation API. Essentially it works by checking that the input provided by the user satisfies all the constraints you define in your HTML.
For example, let's say you'd like the Username to always be present and only contain upper and lowercase letters.
Here's a full example in React (browser):
function App() {
const handleSubmit = event => {
event.preventDefault();
const form = event.target;
const nameInput = document.querySelector('[name="Username"]');
nameInput.addEventListener('input', () => {
nameInput.setCustomValidity('');
nameInput.checkValidity();
});
nameInput.addEventListener('invalid', () => {
if (nameInput.value === '') {
nameInput.setCustomValidity('Enter your username!');
} else {
nameInput.setCustomValidity('Usernames can only contain upper and lowercase letters. Try again!');
}
});
}
return (
<form method="POST" action="/example.php" onSubmit={ handleSubmit }>
<input name="Username" required type="text" pattern="[A-Za-z]+" />
<input required name="Password" type="Password" />
<input type="submit" className="btn-login" />
</form>
);
}
ReactDOM.render(
<App />,
document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Notice how I added pattern="[A-Za-z]+" to the Username field. Simple and declarative.
By the way, you may also want to use AJAX to POST the data to /example.php—nowadays you can use the Fetch API, it's present in all modern browsers.

Related

Why is my handleChange method being rejected by React?

I am trying to do a simple form task to try and learn React Forms but I am having a hard time understanding the syntax of it.
When I try the following code it works no problem:
import React, { useState } from "react";
function InputForm() {
const [emailValue, setEmailValue] = useState("");
console.log(emailValue);
return (
<>
<form>
<label>
Email:
<input
type="text"
name="input"
value={emailValue}
placeholder="type your email"
onChange={(e) => setEmailValue(e.target.value)}
/>
</label>
<br />
<br />
<button type="submit" name="test">
Submit Email
</button>
</form>
</>
);
}
export default InputForm;
However, when I try to clean it up so that there is not logic within the return, I get an error when I define my handleChange method.
import React, { useState } from "react";
function InputForm() {
const [emailValue, setEmailValue] = useState("");
handleChange(e) {
const { name, value } = e.target;
setEmailValue({ [name]: value });
};
console.log(emailValue);
return (
<>
<form>
<label>
Email:
<input
type="text"
name="input"
value={emailValue}
placeholder="type your email"
onChange={handleChange}
/>
</label>
<br />
<br />
<button type="submit" name="test">
Submit Email
</button>
</form>
</>
);
}
export default InputForm;
Can someone please explain why doing it this way doesn't work? The error I'm getting is that React is not expecting the { bracket after handleChange(e)... so the console error messages are useless in trying to figure out why it's not accepting it.
Thanks!
It's not React rejecting anything, it's just that, well, that's not correct JavaScript syntax.
You'll want
function InputForm() {
const [emailValue, setEmailValue] = useState("");
const handleChange = (e) {
const { name, value } = e.target;
setEmailValue({ [name]: value });
};
// ...
(and even so you're mixing and matching state types -- you have a state atom that's ostensibly a string (since you initialize it with a "") and then you assign an object into it... You may be looking for setEmailValue(value); there.)

ReactJS On submit change classes of button and input field

I have a form and when I "Submit" the form I want to add an attribute and some extra classes to the "submit" button and the input field
This is my handleSubmit function
handleSubmit = event => {
event.preventDefault();
const formData = new FormData(event.target);
axios.post(`MyPostUrl`,formData)
.then(res => {
})
}
This is my form
<form onSubmit={this.handleSubmit} method="POST">
<div className="form-row">
<input required min="1" max="10" name="grade" className="form-control col-md-5" type="number" />
<button className="btn btn-outline-primary col-md-6">
Grade
</button>
</div>
</form>
So in let's say jQuery i could just go $(this).find("someClass") and do what ever i need to do with it. How can i achieve this with React?
What I'm trying to do is change the input class to col-md-12 and add an disabled attribute and I want to remove the button on submit
And I have a lot of forms since I've mapped over an object
Consider an example like this: https://codesandbox.io/s/throbbing-bird-ob89o
The idea is to use your component-state to control what classes, styles and attributes to use for your markup.
In this case, we define a submitted state and depending on its Boolean-value, we can use ternary operators to toggle the code we want to render.
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class App extends React.Component {
state = {
grade: "",
submitted: false
};
handleSubmit = e => {
e.preventDefault();
this.setState({
submitted: true
});
};
handleOnChange = e => {
this.setState({
[e.target.name]: e.target.value
});
};
render() {
const { submitted, grade } = this.state;
return (
<form onSubmit={this.handleSubmit} method="POST">
<div className="form-row">
<input
required
onChange={this.handleOnChange}
min="1"
max="10"
name="grade"
className={`form-control ${submitted ? "col-md-12" : "col-md-5"}`}
value={grade}
type="number"
disabled={submitted}
/>
{!submitted ? (
<button className="btn btn-outline-primary col-md-6">Grade</button>
) : (
""
)}
</div>
</form>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
When you submit the form, we toggle the submitted state to true. Our component re-renders and that recalculates all the ternary operators in our mark-up like ${submitted ? "col-md-12" : "col-md-5"} and etc.
You would have to use react states for managing classes too.
e.g:
<button className={this.state.buttonClass}>
Grade
</button>
Better yet, create a wrapper component around it so that these actions can be controlled via props *e.g disabled={true} would add class

Redux form cannot type

I cannot type in the text input of redux form.
it's a very minimal form
function Login({ handleSubmit, handleChange }) {
const [username, setUsername] = useState(undefined);
const [password, setPassword] = useState(undefined);
const onSubmit = (e) => {
console.log(e);
console.log(username);
console.log(password);
};
console.log(handleSubmit);
return (
<Container>
<div className={styles.centered}>
<div className={styles.form}>
<div className={styles.title}>
<H3>Login</H3>
</div>
<form onSubmit={() => handleSubmit(onSubmit)} className={styles.flexColumn}>
<div className={styles.username}>
<P>username</P>
<Field name="username" component="input" type="text" className={styles.input} />
</div>
<div className={styles.password}>
<P>password</P>
<Field name="password" component="input" type="password" className={styles.input} />
</div>
<div className={styles.downSection}>
<Flex>
<P>
Serve Aiuto?
</P>
<a href="#">
<div className={styles.contactLink}>
<P>Contattaci</P>
</div>
</a>
</Flex>
<Button type="submit" text="Accedi" />
</div>
</form>
</div>
</div>
</Container>
);
}
const mapDispatchToProps = {
login: loginAction,
};
const enhance = compose(
connect(null, mapDispatchToProps),
reduxForm({ form: 'login' }),
);
export default enhance(Login);
The handleSubmit doesn't work, i cannot console.log anything.
I tried to see the documentation and tried to search some answer on SO but i didn't find an answer.
Could you please tell me where is the error ? thanks.
So give this a try, let's leave enhance out, I don't know what it does honestly so let's try this type of Login configuration where we turn the component into a class-based one which is good practice anyway since you are receiving inputs from a user.
I do realize you are using useState which is some of the cool new features with React, but what I am recommending is to put together a less complex and conventional setup with a class-based component like so:
import React, { Component } from "react";
import { reduxForm, Field } from "redux-form";
class Login extends Component {
render() {
return (
<form>
<fieldset>
<label>Email</label>
<Field
name="email"
type="text"
component="input"
/>
</fieldset>
<fieldset>
<label>Password</label>
<Field
name="password"
type="password"
component="input"
/>
</fieldset>
</form>
);
}
}
export default reduxForm({ form: "login" })(Login);
Use this to check to see if you can now type into your inputs and then start adding stuff back in and test it every single time until you find the cause of the problem.
Try first just to handle the event
<form onSubmit={onSubmit} className={styles.flexColumn}>
after that try using the this in the function onsubmit and remove the const
onSubmit(event){
console.log(e);
console.log(username);
console.log(password);
this.handleSubmit(event.target.value);
};
after several hours and a special night of bug fixing i discovered the problem:
it was in one import, exactly:
import { Field, reduxForm } from 'redux-form/immutable';
and not
import { Field, reduxForm } from 'redux-form';
this was completely unexpected, i was pretty sure that the mistake was in the body of the component, not in the import.
the structure of the file was ok.

AutoFocus doesn't work in React

I have a problem with autoFocus. It doesn't work for me, but using it:
<input onChange={this.handleName} value={this.state.name} placeholder="Name..." type="text" autoFocus />
None of these worked for me:
<input type="text" autoFocus .../>
<input type="text" autoFocus={true} .../>
<input type="text" autoFocus="true" .../>
<input type="text" autoFocus="autofocus" .../>
…even though in each case, the web inspector showed that <input type="text" autofocus .../> was rendered 🤔
Perhaps it's because of this phenomenon, I'm not sure:
If you render your React component into a detached element, React will call focus() too soon. This will result in the input not focusing when your React tree gets added to the DOM.
This did work for me:
import React, { useRef, useEffect } from "react";
export default function SignIn() {
const inputElement = useRef(null);
useEffect(() => {
if (inputElement.current) {
inputElement.current.focus();
}
}, []);
return (
<div>
<form action="...">
<input
ref={inputElement} // yes, this is working in Chrome on Mac
type="text" // allows username also; type 'email' woud insist on '#' sign
name="email"
placeholder="Email address"
autoComplete="email"
required
...
/>
</form>
</div>
);
}
That's strategy #2 from Daniel Johnson
Likely something else you are doing that is causing it to fail. It works fine in this simple example:
const App = React.createClass({
render() {
return (
<input
placeholder = "Name..."
type = "text"
autoFocus
/ >
);
}
});
ReactDOM.render( <
App / > ,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
For React function components when you get the error
Warning: Function components cannot be given refs. Attempts to access
this ref will fail. Did you mean to use React.forwardRef()?
import React, { useEffect, useRef } from 'react';
const InputField = () => {
const inputElement = useRef(null);
useEffect(() => {
inputElement.current?.focus();
}, []);
return (
<form action="...">
<input type="text" innerRef={inputElement} />
</form>
);
};
export default InputField;
If you use typescript and the compiler complains
Property 'focus' does not exist on type 'never'.ts(2339)
initialize inputElement with
const inputElement = useRef<HTMLInputElement>(null);
I had two Input's which I applied autoFocus to, one worked and the other didn't. They were both reactstrap Input fields:
import { Button, Input } from 'reactstrap';
I discovered that one had a type and no name, which was the one that worked. So I changed the other to be the same and it started working:
<Input
autoFocus="autofocus"
id="code"
type="text"
value={props.codeValue}
onChange={props.onCodeChange}
onKeyPress={event => {
if (event.key === 'Enter') {
confirmCode();
}
}}
/>
place that "autoFocus" infront of "input"
<input autoFocus type='text' ...others />
idk but this worked for me !
This is what worked for me on the functional react component as the autoFocus attribute did not work out of the box:
import React, { useCallback } from 'react';
const FeebackForm = () => {
const autoFocusFn = useCallback(element => (element ? element.focus() : null), []);
return (
<form action="...">
<input type="text" name="customerName" ref={autoFocusFn} />
</form>
);
};
export default FeebackForm;
If you're working on a conditional input component that appears post page is loaded on some user interaction, use react cleanup design to focus the input element.
jsx:
{ this.state.showInput && <input ref={ref => {this.inputRef = ref}} /> }
Class components:
this.setState({showInput: true},
() => {
this.inputRef && this.inputRef.focus()
}
)
Functional components:
useEffect(() => {
return () => {
this.inputRef && this.inputRef.focus()
}
}, [showInput])
If auto focus doesn't work for you then you can try using the .focus() function of javascript, which will always work :)
componentDidMount() {
document.getElementById("name").focus();
}
<input id="name" onChange={this.handleName} value={this.state.name} placeholder="Name..." type="text" autoFocus />

Highly reusable react component without any code change and use only properties

I would like to create a component which I can reuse also for other projects without any code change (only by passing different properties).
A small example:
I have a login form which has a username input and a password input which can look for example like this:
class Login extends Component {
static propTypes = {
login: PropTypes.func.isRequired,
defaultEmailValue: PropTypes.string,
defaultPasswordValue: PropTypes.string,
};
handleSubmit = (event) => {
if (event) {
event.preventDefault();
}
const username = this.refs.username;
const password = this.refs.password;
this.props.login(username.value, password.value);
};
render() {
const {
defaultEmailValue,
defaultPasswordValue,
} = this.props;
return (
<form method="post">
<input defaultValue={defaultEmailValue} ref="username" type="email" />
<input defaultValue={defaultPasswordValue} ref="password" type="password" />
<button onClick={this.handleSubmit} type="submit">Submit</button>
</form>
);
}
}
This is the minimal version of a login form, but what to do when I want to extend the render function to add container components like this (added column tags):
class Login extends Component {
/*....*/
render() {
const {
defaultEmailValue,
defaultPasswordValue,
} = this.props;
return (
<form method="post">
<div class="row">
<div class="col-md-6">
<input defaultValue={defaultEmailValue} ref="username" type="email" />
</div>
<div class="col-md-6">
<input defaultValue={defaultPasswordValue} ref="password" type="password" />
</div>
</div>
<button onClick={this.handleSubmit} type="submit">Submit</button>
</form>
);
}
}
Therefore I have always to modify the render function. Is there a good possibility to do this only with properties?
I estimated to do this with a Wrapper-Component over the Login component but then I have always rewrite the complete render function.
The next possible solution I thought about is to pass wrapper component classes through properties which can be rendered. But is this so a good solution or is this bad practice?
Unfortunately, I found no real solution for this tutorial in the internet and therefore I try it here. Thanks in advance :-)
Is there a good possibility to do this only with properties?
Representational Components are exactly for this kind of things.
export default const LoginForm = (/**props**/ {username, email, submitHandler, errors}) => {
return (
<form>
{/* as usual */}
</form>
)
}
use in your ContainerComponent:
...
render() {
return (
<div className="loginWrapper">
<LoginForm ...this.props ...this.state ...whatever username="pete" />
</div>
)
}
...

Resources