Un EditForm es un componente Blazor que crea un formulario y distribuye su contexto de edición a los campos descendientes.
Hasta ahora, si queríamos un input, usábamos la etiqueta HTML <input> y el binding @bind. Funciona, sí. Pero un formulario real es mucho más que un montón de inputs sueltos.
Un formulario necesita saber:
- ¿Están todos los datos rellenos?
- ¿Son válidos los formatos (email, teléfono)?
- ¿Ha modificado el usuario algún campo o el formulario está “limpio” (pristine)?
Hacer estas comprobaciones a mano resulta repetitivo. EditForm coordina el modelo, el estado de los campos y la validación.
Qué gestiona EditForm
EditForm es un componente nativo de Blazor que actúa como contenedor y orquestador. Su misión es gestionar el estado de edición de un objeto.
En un componente interactivo, EditForm procesa el envío mediante un manejador C# sin recargar el documento. En SSR estático, el formulario realiza una petición al servidor y el componente procesa los datos recibidos.
El modelo
En Blazor, los formularios están basados en modelos. No pensamos en “el input tal”, pensamos en “el objeto tal”.
Para usar un EditForm, primero necesitamos una clase C# que represente los datos que queremos capturar.
public class ContactoModel
{
public string Nombre { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public int Edad { get; set; }
}Sintaxis básica
Para crear el formulario, usamos la etiqueta <EditForm> y le asignamos nuestro objeto al parámetro Model.
<EditForm Model="miContacto" OnValidSubmit="GuardarDatos" FormName="contacto">
<p>Formulario para: @miContacto.Nombre</p>
<button type="submit">Enviar</button>
</EditForm>
@code {
private ContactoModel miContacto = new ContactoModel();
private void GuardarDatos()
{
Console.WriteLine("Guardando en base de datos...");
}
}Al asignar el Model, Blazor crea internamente un objeto llamado EditContext. Este es el cerebro invisible que rastrea qué campos han cambiado y si hay errores de validación.
Gestionar el envío
Los tres eventos de envío que ofrece EditForm suelen crear confusión. No debes usarlos todos a la vez.
OnValidSubmit
Este evento se dispara solo si el formulario es válido. Si usas validación (que veremos pronto) y el usuario pone un email incorrecto, este método NO se ejecutará.
Es genial porque dentro del método GuardarDatos te ahorras comprobar if (isValid). Blazor ya lo ha hecho por ti.
<EditForm Model="@modelo" OnValidSubmit="HandleValidSubmit">OnInvalidSubmit
Es el opuesto. Se dispara cuando el usuario intenta enviar, pero hay errores de validación. Lo solemos usar para mostrar una notificación tipo “Por favor, revisa los campos en rojo” o para hacer scroll hasta el primer error.
<EditForm Model="@modelo" OnValidSubmit="Save" OnInvalidSubmit="ShowError">OnSubmit para control manual
Este evento se dispara siempre, sea válido o no. No puedes combinar OnSubmit con OnValidSubmit o OnInvalidSubmit en el mismo formulario.
Úsalo solo si necesitas un control total y quieres validar manualmente dentro de tu código.
private void HandleSubmit(EditContext context)
{
if (context.Validate()) // Validamos manualmente
{
// Guardar
}
else
{
// Error
}
}Usa OnValidSubmit cuando quieras ejecutar la operación únicamente después de validar. Reserva OnSubmit para flujos que necesiten controlar la llamada a EditContext.Validate().
Protección antiforgery
En una Blazor Web App, EditForm añade automáticamente el componente de antiforgery y el formulario exige un token válido. Esta protección es especialmente relevante para los envíos que procesa el servidor.
El token protege frente a ataques CSRF (Cross-Site Request Forgery). Mantén también app.UseAntiforgery() en el pipeline generado por la plantilla.
¿Dónde están los Inputs?
Un <input @bind="..."> normal puede actualizar el modelo, pero no notifica al EditContext con la información de campo que necesitan la validación y las clases CSS automáticas.
El EditForm necesita saber qué inputs están modificando su modelo para poder marcarlos en rojo si fallan. Para eso, Blazor nos proporciona una serie de componentes envoltorios:
InputTextInputNumberInputDateInputSelect- … y más.
Ejemplo completo
Vamos a ver un esqueleto funcional. Aunque aún no hemos profundizado en los componentes Input*, aquí puedes ver cómo encajan las piezas.
<h3>Nuevo Cliente</h3>
<EditForm Model="cliente" OnValidSubmit="CrearCliente" FormName="nuevo-cliente">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="mb-3">
<label>Nombre:</label>
<InputText class="form-control" @bind-Value="cliente.Nombre" />
</div>
<div class="mb-3">
<label>Email:</label>
<InputText class="form-control" @bind-Value="cliente.Email" />
</div>
<button type="submit" class="btn btn-primary">Registrar</button>
</EditForm>
@if (enviado)
{
<div class="alert alert-success mt-3">¡Cliente creado con éxito!</div>
}
@code {
public class ClienteDto
{
public string Nombre { get; set; } = "";
public string Email { get; set; } = "";
}
private ClienteDto cliente = new ClienteDto();
private bool enviado = false;
private async Task CrearCliente()
{
// Simulamos una llamada asíncrona a API
await Task.Delay(1000);
enviado = true;
Console.WriteLine($"Cliente {cliente.Nombre} procesado.");
}
}