3. Řešení úkolu

Třída Kniha

using System.ComponentModel.DataAnnotations;

namespace ValidaceDat.Models
{
    public class Kniha
    {
        [Required(ErrorMessage = "Název knihy musí být vyplněn.")]
        public string Nazev { get; set; } = "";

        [Required(ErrorMessage = "Zadejte jméno autora (minimálně 3 znaky).")]
        [MinLength(3, ErrorMessage = "Zadejte jméno autora (minimálně 3 znaky).")]
        public string Autor { get; set; } = "";

        // Poznámka: Atribut [Range] vyžaduje konstantní hodnoty.
        // Pro zjednodušení v rámci tohoto úkolu používáme pevný horní limit (např. aktuální rok 2026).
        [Range(1440, 2026, ErrorMessage = "Rok vydání musí být reálný letopočet (1440 - současnost).")]
        public int RokVydani { get; set; }

  // Počet stran musí být minimálně 1. Horní limit můžeme nastavit na maximální hodnotu datového typu int.
        [Range(1, int.MaxValue, ErrorMessage = "Kniha musí mít alespoň jednu stranu.")]
        public int PocetStran { get; set; }
    }
}

Třída Kniha definuje datový model pro uložení informací o novém záznamu. Importem jmenného prostoru System.ComponentModel.DataAnnotations získáváme možnost aplikovat na jednotlivé vlastnosti přímočará validační pravidla.

Vlastnosti Nazev a Autor jsou pomocí atributu [Required] označeny jako povinné, takže je uživatel nesmí vynechat. U autora se navíc nachází atribut [MinLength], který hlídá, aby zadaný text obsahoval alespoň tři znaky.

U číselných vlastností RokVydani a PocetStran je použit atribut [Range]. Ten zajišťuje, že uživatel zadá číselnou hodnotu v logickém a předem definovaném rozpětí (např. alespoň 1 stranu). Všechny tyto atributy zároveň obsahují parametr ErrorMessage, ve kterém je připravena chybová hláška. Ta se automaticky propíše do uživatelského rozhraní v případě, že formulářová data poruší dané pravidlo.


Razor komponenta

@page "/"
<PageTitle>Přidat knihu</PageTitle>

<div class="card shadow-sm p-4 mb-4" style="max-width: 600px;">
    <h2 class="mb-4">Přidat novou knihu do deníku</h2>

    <EditForm Model="novaKniha" OnValidSubmit="UlozitKnihu">
        <DataAnnotationsValidator />

        <div class="mb-3">
            <label class="form-label">Název knihy:</label>
            <InputText @bind-Value="novaKniha.Nazev" class="form-control" />
            <ValidationMessage For="@(() => novaKniha.Nazev)" class="text-danger" />
        </div>

        <div class="mb-3">
            <label class="form-label">Autor:</label>
            <InputText @bind-Value="novaKniha.Autor" class="form-control" />
            <ValidationMessage For="@(() => novaKniha.Autor)" class="text-danger" />
        </div>

        <div class="mb-3">
            <label class="form-label">Rok vydání:</label>
            <InputNumber @bind-Value="novaKniha.RokVydani" class="form-control" />
            <ValidationMessage For="@(() => novaKniha.RokVydani)" class="text-danger" />
        </div>

        <div class="mb-3">
            <label class="form-label">Počet stran:</label>
            <InputNumber @bind-Value="novaKniha.PocetStran" class="form-control" />
            <ValidationMessage For="@(() => novaKniha.PocetStran)" class="text-danger" />
        </div>

        <div class="mt-4">
            <button type="submit" class="btn btn-primary">Uložit do deníku</button>
        </div>
    </EditForm>
</div>

@if (seznamKnih.Count > 0)
{
    <div class="card shadow-sm p-4" style="max-width: 600px;">
        <h3 class="mb-3">Můj čtenářský deník</h3>
        <table class="table table-striped table-hover">
            <thead class="table-dark">
                <tr>
                    <th>Název</th>
                    <th>Autor</th>
                    <th>Rok</th>
                    <th>Stran</th>
                </tr>
            </thead>
            <tbody>
                @foreach (var kniha in seznamKnih)
                {
                    <tr>
                        <td><strong>@kniha.Nazev</strong></td>
                        <td>@kniha.Autor</td>
                        <td>@kniha.RokVydani</td>
                        <td>@kniha.PocetStran</td>
                    </tr>
                }
            </tbody>
        </table>
    </div>
}

@code {
    // Vytvoření prázdné instance knihy pro napojení na formulář (předvyplníme aktuální rok)
    private Models.Kniha novaKniha = new Models.Kniha() { RokVydani = 2024 };

    // Lokální seznam, do kterého se budou ukládat platné knihy
    private List<Models.Kniha> seznamKnih = new List<Models.Kniha>();

    // Tato metoda se spustí POUZE tehdy, pokud všechna data projdou validací
    private void UlozitKnihu()
    {
        // 1. Přidáme vyplněnou knihu do našeho seznamu
        seznamKnih.Add(novaKniha);

        // 2. Vyčistíme formulář vytvořením nového, prázdného objektu pro další zadávání
        novaKniha = new Models.Kniha() { RokVydani = 2024 };
    }
}

Základem této stránky je komponenta <EditForm>, která nahrazuje klasický HTML formulář a je napojena přímo na objekt novaKniha. Klíčovým prvkem je událost OnValidSubmit, která zaručuje, že se metoda pro uložení dat spustí pouze v případě, kdy uživatel vyplní formulář zcela bez chyb. Samotné hlídání pravidel definovaných v modelu aktivuje nenápadná, ale nezbytná značka <DataAnnotationsValidator />.

Jednotlivá vstupní pole využívají speciální Blazor prvky (jako <InputText> nebo <InputNumber>), které jsou obousměrně svázány s daty pomocí @bind-Value. Pod každým z nich je umístěna značka <ValidationMessage>. Právě zde se automaticky vykreslí červená chybová hláška z modelu, pokud zadaná data nesplní naše kritéria.

V sekci @code se nachází logika stránky. Pokud validace proběhne úspěšně, zavolá se metoda UlozitKnihu. Ta přidá aktuálně vyplněnou knihu do připravené kolekce seznamKnih a ihned formulář "vyčistí" tím, že do proměnné vloží úplně novou, prázdnou instanci. Jakmile je v seznamu alespoň jeden záznam, díky podmínce @if (seznamKnih.Count > 0) se na obrazovce automaticky vykreslí i HTML tabulka s přehledem přečtených knih.