Lärarguide · Lektion 5 av 8

Formulär & validering

Mål: studenten kan bygga formulär med EditForm och DataAnnotations som ger bra UX. Examinationsuppgiften presenteras under sista 15 minuterna.

V5
Vecka
2,5 h
Total tid
~50 min
Teori
~60 min
Workshop
Studentmaterial 05-formular-validering.html + 09-examination.html (delas idag).
Kompletterande resurser

Lektionens mål

Agenda (150 min)

0:00
Check-in.
0:10
Teori: EditForm-anatomi, Model + OnValidSubmit, InputXxx-komponenter.
0:35
Teori: DataAnnotations + custom IValidatableObject.
1:00
Paus 15 min
1:15
Workshop: registrera-användare-formulär med all validering.
2:15
Examinationen presenteras — gå igenom 09-examination.html grundligt.
2:30
Slut

Talartips per sektion

EditContext vs Model: börja enkelt med Model. Nämn EditContext bara om någon frågar — det är för avancerade fall (manuella validity-checks, fält-för-fält-validering).
OnValidSubmit vs OnSubmit: Använd alltid OnValidSubmit + DataAnnotationsValidator. OnSubmit skickar oavsett validering, vilket nästan aldrig är vad du vill.
Examinationen: avsätt minst 15 min för frågor. Visa exempel på en typisk "G"-app vs en "VG"-app. Var tydlig med tidsåtgång och deadline.

Workshop — guide för läraren

  1. Skapa RegisterModel med Email, Password, ConfirmPassword, Age, AcceptTerms.
  2. Lägg på DataAnnotations: Required, EmailAddress, MinLength, Range(18, 120), [Compare("Password")].
  3. Bygg ett EditForm med InputText, InputNumber, InputCheckbox och ValidationSummary.
  4. Visa felmeddelanden under varje fält med ValidationMessage For="@(() => model.Email)".
  5. Lägg till IValidatableObject som kollar att lösenord inte innehåller användarnamnet.
public class RegisterModel : IValidatableObject
{
  [Required, EmailAddress] public string Email { get; set; } = "";
  [Required, MinLength(8)] public string Password { get; set; } = "";
  [Compare(nameof(Password))] public string ConfirmPassword { get; set; } = "";
  [Range(18, 120)] public int Age { get; set; }
  [Range(typeof(bool), "true", "true", ErrorMessage = "Måste acceptera villkor")]
  public bool AcceptTerms { get; set; }

  public IEnumerable<ValidationResult> Validate(ValidationContext ctx)
  {
    if (!string.IsNullOrEmpty(Email) && Password.Contains(Email.Split('@')[0]))
      yield return new("Lösenord får ej innehålla användarnamn", new[] { nameof(Password) });
  }
}

För snabba

  • Bygg ett InputFile-fält som accepterar maximal 1 MB bild.
  • Implementera realtidsvalidering (validering vid varje knapptryck istället för bara vid submit).

För dem som behöver stöd

  • Förbered RegisterModel med tomma fält och bara Required-attributet — låt dem lägga till resten själva.
  • Visa ett färdigt exempel först, låt dem härma.

Vanliga frågor

Mina valideringsmeddelanden visas inte — varför?
Glömt <DataAnnotationsValidator /> inuti EditForm. Utan den körs ingen validering.
Kan jag använda FluentValidation?
Ja, via Blazored.FluentValidation-paketet. Bra alternativ för komplex validering. Vi visar bara DataAnnotations i denna kurs.
Hur kombinerar jag två fält i en valideringsregel?
IValidatableObject är det enklaste sättet — du har access till hela modellen i Validate-metoden.
Varför validerar inte mina OrderItems i listan?
Klassiska DataAnnotationsValidator går inte ner i nested objects eller collections. I .NET 10: registrera builder.Services.AddValidation() i Program.cs och sätt [ValidatableType] på rotklassen. Viktigt: modellen måste ligga i en .cs-fil, inte i en .razor-fil — källgeneratorn ser inte klasser deklarerade inuti Razor.
Viktigt om examinationen Var tydlig med att inga UI-bibliotek (MudBlazor, Radzen, Syncfusion) är tillåtna i grundinlämningen. Det är för att säkerställa att de förstår grunderna.
Hemuppgift Övningar 1–4. Påbörja examinationsprojektet — välj domän och skissa datamodell + sidor till L6.
Förberedelse till nästa lektion Be alla ha en domän vald inför L6. Då blir state & DI-workshopen direkt tillämplig på deras eget projekt.

← L4 L6 — State & DI →