Theorie
Eine Form ist eine Sammlung von Eingabefelder
-
Form
- Werte können mit
Stateverwaltet werden - Alternative Extration mit ref oder mit FormData und nativen Browser Funktionen
- Werte können mit
-
Validierung
- kann sehr schwierig sein aufgrund des Triggers
- keystroke kann zu verfrühten Fehler führen
- lost focus eventuell eine zu lange Fehlermeldung
- mit form Bestätigung eventuell zu spät
Beispiel für eine Form
//Login.jsx
export default function Login() {
function handleSubmit() {
event.preventDefault();
console.log('Submitted!');
}
return (
<form onSubmit={handleSubmit}>
<h2>Login</h2>
<div className="control-row">
<div className="control no-margin">
<label htmlFor="email">Email</label>
<input id="email" type="email" name="email" />
</div>
<div className="control no-margin">
<label htmlFor="password">Password</label>
<input id="password" type="password" name="password" />
</div>
</div>
<p className="form-actions">
<button className="button button-flat">Reset</button>
<button className="button" >Login</button>
</p>
</form>
);
}
Generischer Handler für Benutzer Eingaben
import { useState } from "react";
export default function Login() {
const [enteredValues, setEnteredValues] = useState({
email: '',
password: ''
});
function handleSubmit() {
event.preventDefault();
console.log(enteredValues);
}
function handleInputChange(event, identifier) {
setEnteredValues(prevValues => ({
...prevValues,
[identifier]: event.target.value
}))
}
return (
<form onSubmit={handleSubmit}>
<h2>Login</h2>
<div className="control-row">
<div className="control no-margin">
<label htmlFor="email">Email</label>
<input id="email" type="email" name="email" onChange={(event) => handleInputChange(event,'email')} value={enteredValues.email} />
</div>
<div className="control no-margin">
<label htmlFor="password">Password</label>
<input id="password" type="password" name="password" onChange={(event) => handleInputChange(event,'password')} value={enteredValues.password}/>
</div>
</div>
<p className="form-actions">
<button className="button button-flat">Reset</button>
<button className="button" >Login</button>
</p>
</form>
);
}
Komplexere Forms mithilfe von FormData (native Browser Unterstützung)
- Checkboxen (mehrere Werte) müssen mit getAll geholt werden, nicht in fromEntries inbegriffen
//Signup.jsx
export default function Signup() {
function handleSubmit(event) {
event.preventDefault();
const fd = new FormData(event.target);
const acquisitionChannel = fd.getAll('acquisition');
const data = Object.fromEntries(fd.entries());
data.acquisition = acquisitionChannel;
console.log(data);
}
return (
<form onSubmit={handleSubmit}>
<h2>Welcome on board!</h2>
<p>We just need a little bit of data from you to get you started 🚀</p>
<div className="control">
<label htmlFor="email">Email</label>
<input id="email" type="email" name="email" />
</div>
<div className="control-row">
<div className="control">
<label htmlFor="password">Password</label>
<input id="password" type="password" name="password" />
</div>
<div className="control">
<label htmlFor="confirm-password">Confirm Password</label>
<input
id="confirm-password"
type="password"
name="confirm-password"
/>
</div>
</div>
<hr />
<div className="control-row">
<div className="control">
<label htmlFor="first-name">First Name</label>
<input type="text" id="first-name" name="first-name" />
</div>
<div className="control">
<label htmlFor="last-name">Last Name</label>
<input type="text" id="last-name" name="last-name" />
</div>
</div>
<div className="control">
<label htmlFor="phone">What best describes your role?</label>
<select id="role" name="role">
<option value="student">Student</option>
<option value="teacher">Teacher</option>
<option value="employee">Employee</option>
<option value="founder">Founder</option>
<option value="other">Other</option>
</select>
</div>
<fieldset>
<legend>How did you find us?</legend>
<div className="control">
<input
type="checkbox"
id="google"
name="acquisition"
value="google"
/>
<label htmlFor="google">Google</label>
</div>
<div className="control">
<input
type="checkbox"
id="friend"
name="acquisition"
value="friend"
/>
<label htmlFor="friend">Referred by friend</label>
</div>
<div className="control">
<input type="checkbox" id="other" name="acquisition" value="other" />
<label htmlFor="other">Other</label>
</div>
</fieldset>
<div className="control">
<label htmlFor="terms-and-conditions">
<input type="checkbox" id="terms-and-conditions" name="terms" />I
agree to the terms and conditions
</label>
</div>
<p className="form-actions">
<button type="reset" className="button button-flat">
Reset
</button>
<button type="submit" className="button">
Sign up
</button>
</p>
</form>
);
}
Zurücksetzen von Werten
//Signup.jsx
function handleSubmit(event) {
event.preventDefault();
const fd = new FormData(event.target);
const acquisitionChannel = fd.getAll('acquisition');
const data = Object.fromEntries(fd.entries());
data.acquisition = acquisitionChannel;
console.log(data);
event.target.reset();
}
<form onSubmit={handleSubmit}>
<p className="form-actions">
<button type="reset" className="button button-flat">
Reset
</button>
<button type="submit" className="button">
Sign up
</button>
</p>
</form>
Einzelnde EingabeFelder
-
Validierung nach dem Eintippen
- geht nur mit einem State Ansatz
-
Validierung mit Built-in Props
- required
Wiederverwendbare Komponente
//Input.jsx
export default function Input({ label, id, error, ...props }) {
return (
<div className="control no-margin">
<label htmlFor={id}>Email</label>
<input
id={id}
{...props}
/>
<div className="control-error">{error && <p>{error}</p>}</div>
</div>
);
}
//StateLogin.jsx
<Input
label="Email"
id="email"
type="email"
name="email"
onChange={(event) => handleInputChange(event, 'email')}
value={enteredValues.email}
onBlur={() => handleInputBlur('email')}
error={emailIsInvalid && 'Please enter a valid email!'}
/>
Auslagerung Validierung
//validation.js
export function isEmail(value) {
return value.includes('@');
}
export function isNotEmpty(value) {
return value.trim() !== '';
}
export function hasMinLength(value, minLength) {
return value.length >= minLength;
}
export function isEqualsToOtherValue(value, otherValue) {
return value === otherValue;
}
Eigenen Hook für Validerung erstellen
//useInput.js
import { useState } from "react";
export function useInput(defaultValue, validationFn) {
const [enteredValue, setEnteredValue] = useState(defaultValue);
const [didEdit, setDidEdit] = useState(false);
const valueIsValid = validationFn(enteredValue);
function handleInputChange(event) {
setEnteredValue(event.target.value);
setDidEdit(false);
}
function handleInputBlur() {
setDidEdit(true);
}
return {
value: enteredValue,
handleInputChange,
handleInputBlur,
hasError: didEdit && !valueIsValid
};
}
//StateLogin.jsx
import Input from "./Input";
import { isEmail, isNotEmpty, hasMinLength } from '../util/validation.js'
import { useInput } from "../hooks/useInput.js";
export default function Login() {
//const {value: emailValue, handleInputChange: handleEmailChange, handleInputBlur: handleEmailBlur} = useInput('', isEmail);
const {
value: emailValue,
handleInputChange: handleEmailChange,
handleInputBlur: handleEmailBlur,
hasError: emailHasError
} = useInput('', (value) => isEmail(value) && isNotEmpty(value));
const {
value: passwordValue,
handleInputChange: handlePasswordChange,
handleInputBlur: handlePasswordBlur,
hasError: passwordHasError
} = useInput('', (value) => hasMinLength(value, 6));
function handleSubmit() {
event.preventDefault();
if (emailHasError || passwordHasError) {
return;
}
console.log(emailValue, passwordValue);
}
return (
<form onSubmit={handleSubmit}>
<h2>Login</h2>
<div className="control-row">
<Input
label="Email"
id="email"
type="email"
name="email"
onChange={handleEmailChange}
value={emailValue}
onBlur={handleEmailBlur}
error={emailHasError && 'Please enter a valid email!'}
/>
<Input
label="Password"
id="password"
type="password"
name="password"
onChange={handlePasswordChange}
value={passwordValue}
onBlur={handlePasswordBlur}
error={passwordHasError && 'Please enter a valid password!'}
/>
</div>
<p className="form-actions">
<button className="button button-flat">Reset</button>
<button className="button" >Login</button>
</p>
</form>
);
}