Del 5 av 8

Formulär & validering

EditForm, Input-komponenterna och DataAnnotations. Vi bygger formulär som validerar både i UI och i C#-modellen.

Lektion 5 — V5. Formulär är en av de tyngsta delarna i affärsappar. Blazor har ett kraftfullt inbyggt formulärsystem som vi tämjer steg för steg.

EditForm — Blazors formulärrot

Ett formulär byggs runt en EditForm som är kopplad till en C#-modell. Inuti formuläret används specialiserade Input*-komponenter som vet hur de ska binda mot egenskaper.

@page "/register"

<EditForm Model="model" OnValidSubmit="HandleSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <div>
        <label>Förnamn</label>
        <InputText @bind-Value="model.FirstName" />
        <ValidationMessage For="@(() => model.FirstName)" />
    </div>

    <div>
        <label>E-post</label>
        <InputText @bind-Value="model.Email" />
        <ValidationMessage For="@(() => model.Email)" />
    </div>

    <button type="submit">Registrera</button>
</EditForm>

@code {
    private RegisterModel model = new();

    private void HandleSubmit()
    {
        Console.WriteLine($"Registrerar {model.FirstName} ({model.Email})");
    }
}

Modellen med DataAnnotations

using System.ComponentModel.DataAnnotations;

public class RegisterModel
{
    [Required(ErrorMessage = "Förnamn krävs")]
    [StringLength(50, MinimumLength = 2)]
    public string FirstName { get; set; } = "";

    [Required, EmailAddress(ErrorMessage = "Ogiltig e-post")]
    public string Email { get; set; } = "";

    [Required, MinLength(8, ErrorMessage = "Lösenord måste vara minst 8 tecken")]
    public string Password { get; set; } = "";

    [Range(18, 120, ErrorMessage = "Ålder måste vara mellan 18 och 120")]
    public int Age { get; set; }

    [Compare(nameof(Password), ErrorMessage = "Lösenorden matchar inte")]
    public string PasswordConfirm { get; set; } = "";
}

Input-komponenterna

KomponentHTML-elementFör typ
InputText<input type="text">string
InputTextArea<textarea>string
InputNumber<input type="number">int, decimal, double
InputDate<input type="date">DateTime, DateOnly
InputCheckbox<input type="checkbox">bool
InputSelect<select>enum, string
InputRadioGroup + InputRadio<input type="radio">enum, string
InputFile<input type="file">Filuppladdning

InputSelect med enum

public enum Roll { Anvandare, Redaktor, Admin }

public class UserModel
{
    [Required] public Roll Roll { get; set; }
}
<InputSelect @bind-Value="model.Roll">
    @foreach (var r in Enum.GetValues<Roll>())
    {
        <option value="@r">@r</option>
    }
</InputSelect>

InputRadioGroup

<InputRadioGroup @bind-Value="model.Roll">
    @foreach (var r in Enum.GetValues<Roll>())
    {
        <label>
            <InputRadio Value="r" /> @r
        </label>
    }
</InputRadioGroup>

EditForm — händelser

HändelseNär den körs
OnValidSubmitVid submit om alla valideringar är OK
OnInvalidSubmitVid submit om det finns valideringsfel
OnSubmitVid submit oavsett validering (manuell hantering)
Använd antingen OnSubmit ELLER OnValidSubmit/OnInvalidSubmit Inte både och. Om du behöver custom valideringslogik vid submit, använd OnSubmit + EditContext.Validate().

Anpassad validering — IValidatableObject

public class BookingModel : IValidatableObject
{
    [Required] public DateTime CheckIn { get; set; }
    [Required] public DateTime CheckOut { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext ctx)
    {
        if (CheckOut <= CheckIn)
        {
            yield return new ValidationResult(
                "Utcheckning måste vara efter incheckning",
                new[] { nameof(CheckOut) });
        }
    }
}

.NET 10: AddValidation & [ValidatableType] — nested validering

I .NET 10 finns en ny, kraftfullare valideringsmotor som klarar nested objects och collections direkt — utan att du behöver skriva egen IValidatableObject. Aktivera den i Program.cs:

// Program.cs
builder.Services.AddValidation();

Märk rotklassen med [ValidatableType]:

// Models/Order.cs  (MÅSTE ligga i en .cs-fil — inte i .razor!)
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Components.Forms;

[ValidatableType]
public class Order
{
    [Required] public string Customer { get; set; } = "";

    [MinLength(1, ErrorMessage = "Minst en orderrad krävs")]
    public List<OrderItem> Items { get; set; } = new();
}

public class OrderItem
{
    [Required] public string ProductName { get; set; } = "";
    [Range(1, 100)] public int Quantity { get; set; }
}

Nu valideras varje OrderItem i listan automatiskt när formuläret submitas — det går inte med klassiska DataAnnotationsValidator ensamt.

.NET 10-nyheter för formulär
I denna kurs Vi börjar med klassiska DataAnnotationsValidator (fungerar fortfarande och är enklast att förstå). När du senare behover validera komplexa modeller med listor — använd AddValidation().

InputFile — ladda upp filer

<InputFile OnChange="HandleSelected" multiple accept=".jpg,.png" />

@if (preview != null)
{
    <img src="@preview" style="max-width:200px" />
}

@code {
    private string? preview;

    private async Task HandleSelected(InputFileChangeEventArgs e)
    {
        var file = e.File;
        using var stream = file.OpenReadStream(maxAllowedSize: 5 * 1024 * 1024);
        using var ms = new MemoryStream();
        await stream.CopyToAsync(ms);
        var base64 = Convert.ToBase64String(ms.ToArray());
        preview = $"data:{file.ContentType};base64,{base64}";
    }
}
Säkerhet — alltid begränsa filstorlek Standardgränsen är 500 KB. Ange alltid maxAllowedSize explicit. Validera även MIME-typ och filändelse på servern, inte bara i UI:t.

Referenser

Elektroniska resurser

Böcker

Övningar

Lös övningarna självständigt. Det finns inget facit — lärandet sker i processen.

  1. Registreringsformulär Bygg ett formulär för att registrera en användare med Förnamn, Efternamn, E-post, Lösenord, Bekräfta lösenord och Ålder. Använd DataAnnotations för alla regler.
  2. Bokningsformulär med custom validering Bygg ett bokningsformulär med incheckning och utcheckning. Använd IValidatableObject för att säkerställa att utcheckning är efter incheckning och att vistelsen är max 14 dagar.
  3. Filuppladdning Skapa en sida där användaren laddar upp en bild (max 2 MB, bara JPG/PNG). Visa förhandsvisning i browsern utan att skicka filen någonstans.
  4. Dynamiskt formulär Bygg ett formulär med en knapp "Lägg till adress" som lägger till ytterligare adressfält. Modellen har en List<Address>. Validera att minst en adress finns.

Soloprojektor

Projekt 1 — Kontaktformulär Bygg ett komplett kontaktformulär med namn, e-post, ärendetyp (radioknappar), meddelande (textarea), prenumerera på nyhetsbrev (checkbox) och GDPR-godkännande. Vid lyckad submit visa en bekräftelsesida.
Projekt 2 — Produktredigerare (fördjupning) Skapa en formulärsida för att skapa/redigera en produkt med namn, beskrivning, pris, kategori (select), bilduppladdning och en lista varianter (dynamiska rader). Validera allt och visa felmeddelanden snyggt.

← Föregående: Routing Nästa: State & DI →