In my react js application i have the next input:
<input required type="text" id="fname" name="fname" value=""/>
In the case above if the form will be submitted the without input value the will appear a message: Please fill in this field
, because it is required. Instead of this text i want to add a custom html element with a different content and style.
I want to check after the form is submitted that this input is required and there is no value. So if there is that scenario then to show a custom element bellow like: <div>No data here</div>
I need to achieve this without using the form
tag just to create a custom input component in React js and to do something like:
export default function Input() {
const ref = React.useRef();
return (
<div className="App">
<input ref={ref} required type="text" id="fname" name="fname" value=""/>
{ref.current.isError ? <div>Message</div> : null}
</div>
);
}
Is this possible to check?
CodePudding user response:
You can use onInvalid
method on input e.g:
function Input() {
const [invalid, setInvalid] = useState<boolean>(false);
const onSubmit = (data: any) => {
setInvalid(false);
console.log(data)
}
return (
<div style={{ margin: '60px'}}>
<form onSubmit={onSubmit}>
<input
id="fname"
name="fname"
required
type="text"
onInvalid={(e) => {
e.preventDefault();
// if you have ref you can obtain reason why this input is invalid
// console.log(ref.current?.validity.valueMissing);
// or just use e.target.validity
setInvalid(true);
}}
/>
<button type="submit">submit</button>
</form>
{invalid && "invalid"}
</div>
);
}
useState
is used here to cause re-render component
Edit: if you don't want to have form
inside Input
component then just move state to parent component e.g:
function Input(props: { invalid: boolean; setInvalid: () => void }) {
const { invalid, setInvalid } = props;
return (
<div style={{ margin: '60px'}}>
<input
id="fname"
name="fname"
required
type="text"
onInvalid={(e) => {
e.preventDefault();
setInvalid();
}}
/>
{invalid && "invalid"}
</div>
);
}
function App() {
const [invalid, setInvalid] = useState<Record<string, boolean>>({});
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
setInvalid({});
console.log(event);
}
return (
<div className="App">
<form onSubmit={handleSubmit}>
<Input invalid={invalid.fname} setInvalid={() => setInvalid(state => ({...state, fname: true}))}/>
<button type="submit">submit</button>
</form>
</div>
);
}
CodePudding user response:
- All you need is to check if the input is empty or not and based on result we are making a decision for printing message.
- All we need is
useState
hook,onSubmit
form validation.
index.js
import React from "react";
import ReactDOM from "react-dom";
import MyInput from "./MyInput.js";
class App extends React.Component {
render() {
return (
<div>
// validate attribute to defind which validation we need
<MyInput validate="email" />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("container"));
MyInput.js
import React, { useState } from "react";
const MyInput = ({ validate }) => {
const [userInput, setUserInput] = useState("");
const [isError, setIsError] = useState(false);
const [errorMessage, setErrorMessage] = useState("");
const handleInput = (e) => {
setUserInput(e.target.value);
setIsError(false);
};
function validateEmail(email) {
var re = /\S @\S \.\S /;
return re.test(email);
}
//you can defind more states such as for password or as per your requirement.
const validateField = (fieldType) => {
switch (fieldType) {
case "email":
if (validateEmail(userInput)) {
setIsError(false);
} else {
setErrorMessage("Need proper email..");
setIsError(true);
}
break;
default:
setIsError(false);
}
};
const handleSubmit = (e) => {
e.preventDefault();
validateField(validate);
};
return (
<form onSubmit={handleSubmit}>
<input type="text" value={userInput} onChange={handleInput} />
{isError ? <p>{errorMessage}</p> : ""}
<input type="submit" />
</form>
);
};
export default MyInput;
Here is working example.
<iframe src="https://codesandbox.io/embed/react-playground-forked-ozgle5?fontsize=14&hidenavigation=1&theme=dark&view=preview" style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;" title="React PlayGround (forked)" allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"></iframe>