Formularios y mutaciones
EmberKit incluye gestión de formularios con validación, estado y envío integrados.
Formulario básico
import { createSignal } from '@emberkit/core';
import { handleFormSubmit } from '@emberkit/core';
function ContactForm() {
const [submitted, setSubmitted] = createSignal(false);
async function onSubmit(event: SubmitEvent) {
await handleFormSubmit(event, {
onSubmit: async (formData) => {
await fetch('/api/contact', {
method: 'POST',
body: formData,
});
setSubmitted(true);
},
onError: (errors) => {
console.error('Validation failed:', errors);
},
});
}
if (submitted()) {
return <div className="alert-success">Message sent!</div>;
}
return (
<form onSubmit={onSubmit}>
<input name="name" placeholder="Name" required />
<input name="email" type="email" placeholder="Email" required />
<textarea name="message" placeholder="Message" required />
<button type="submit">Send</button>
</form>
);
}
Validación
Define un esquema de validación:
import { createFormValidator } from '@emberkit/core';
const validator = createFormValidator({
fields: {
name: {
required: true,
minLength: 2,
maxLength: 50,
},
email: {
required: true,
pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
},
age: {
custom: (value) => {
const n = Number(value);
if (n < 18) return 'Must be at least 18';
if (n > 120) return 'Invalid age';
return null;
},
},
},
});
const errors = validator.validate({ name: '', email: 'bad', age: 15 });
// { name: 'name is required', email: 'email is invalid', age: 'Must be at least 18' }
Validadores integrados
| Nombre del campo | Validación |
|---|---|
email | Coincidencia de patrón para formato email |
url | Coincidencia de patrón para URLs HTTP(S) |
phone | Coincidencia de patrón para números de teléfono |
Estado del formulario
Rastrea el estado manualmente para formularios complejos:
import { createSignal, createFormState, setFieldValue, setFieldError } from '@emberkit/core';
function SignupForm() {
const [state, setState] = createSignal(createFormState({
username: '',
password: '',
}));
function handleChange(name: string, value: string) {
setState(prev => setFieldValue(prev, name, value));
}
return (
<form>
<input
value={state().values.username}
onChange={(e) => handleChange('username', e.target.value)}
/>
{state().errors.username && <span>{state().errors.username}</span>}
</form>
);
}
Mutaciones
Las mutaciones en servidor gestionan cambios de datos:
// src/routes/_api/posts.ts
export async function POST(request: Request) {
const data = await request.json();
// Validate
if (!data.title || !data.content) {
return new Response('Missing fields', { status: 400 });
}
// Save to database
const post = await db.posts.create(data);
return new Response(JSON.stringify(post), {
headers: { 'Content-Type': 'application/json' },
});
}
Mejora progresiva
Mejora progresiva
Los formularios funcionan sin JavaScript. El servidor gestiona el envío cuando JS no está disponible; la validación en cliente toma el control tras la hidratación.
<form action="/api/contact" method="POST">
<input name="name" />
<input name="email" type="email" />
<button type="submit">Send</button>
</form>
Con JavaScript cargado, la validación en cliente se ejecuta primero; luego la mutación se gestiona vía fetch.