Black Friday Black Friday
Black Friday výprodej! Až 80 % extra bodů zdarma! Více informací zde

Lekce 3 - Obsluha formulářů v ASP.NET Core MVC

C# .NET ASP.NET ASP.NET Core Základy ASP.NET Core MVC Obsluha formulářů v ASP.NET Core MVC

ONEbit hosting Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, První webová aplikace v ASP.NET Core MVC, jsme si v praxi vyzkoušeli MVC architekturu a naučili se předávat data z modelu do pohledu. Říkali jsme si, že toto předání probíhá přes speciální kolekci (nejčastěji ViewBag). Existuje však ještě druhý způsob a to je napojení modelu přímo na View, této technice se říká model binding. Ten se hodí zejména při práci s formuláři a vyzkoušíme si ho v dnešním ASP.NET Core tutoriálu. Programovat budeme jednoduchou kalkulačku.

Založíme si novou ASP.NET Core Web Application, kterou pojmenujeme MVCKalkulacka. I když bychom mohli jako minule začít s prázdným template, dnes zvolíme template MVC.

Založení nového ASP.NET MVC projektu

Tím nám budou vygenerovány i jednotlivé složky pro MVC komponenty a nastaveny routy a konfigurace, kterou jsme minule dělali ručně. Bude nám vygenerován i ukázkový projekt obsahující několik sliderů a dokonce i slavnou EU cookie hlášku. Můžete si jej zkusit spustit, minule jsme jej nevyužili, abychom lépe pochopili jak MVC funguje a zbytečně nás nerozptyloval.

Výchozí projekt v ASP.NET Core MVC

My tento projekt nebudeme potřebovat a proto vyprázdníme veškerý obsah složek Models, Controllers a Views v Solution Exploreru, ovšem ponecháme soubor _ViewImports.cshtml, jinak by nám správně nefungovaly tzv. tag helpers (viz dále). Pokud bychom začínali s prázdným projektem jako minule, museli bychom tento soubor přidat ručně. Jako název projektu nepoužívejte jen Kalkulacka, jelikož by kolidoval s názvem naší třídy.

Rovnou si ukažme, jak bude naše hotová kalkulačka vypadat:

Kalkulačka v ASP.NET Core MVC

Model

Začněme opět modelem, kterým bude třída Kalkulacka. Tu si přidejte do složky Models. Modelu přidáme několik veřejných vlastností, konkrétně dvě vstupní čísla, vybranou operaci a výsledek. Poslední vlastností bude list typu SelectListItem, který bude obsahovat možné operace pro pohled. Ten z nich následně vyrenderuje HTML element <select>. List rovnou naplníme v konstruktoru. Nezapomeňte si přidat using Microsoft.AspNetCore.Mvc.Rendering.

public class Kalkulacka
{
        public int Cislo1 { get; set; }
        public int Cislo2 { get; set; }
        public double Vysledek { get; set; }
        public string Operace { get; set; }
        public List<SelectListItem> MozneOperace { get; set; }

        public Kalkulacka()
        {
                MozneOperace = new List<SelectListItem>();
                MozneOperace.Add(new SelectListItem { Text = "Sečti", Value = "+", Selected = true });
                MozneOperace.Add(new SelectListItem { Text = "Odečti", Value = "-" });
                MozneOperace.Add(new SelectListItem { Text = "Vynásob", Value = "*" });
                MozneOperace.Add(new SelectListItem { Text = "Vyděl", Value = "/" });
        }

}

Vlastnost Text třídy SelectListItem je popisek možnosti, který vidí uživatel. Value je hodnota, která se odesílá na server (neměla by obsahovat diakritiku). Můžeme nastavit i vlastnost Selected, která označuje zda má být položka při zobrazení stránky vybraná.

Zbývá jen metoda s nějakou logikou, která podle zvolené Operace a hodnot v Cislo1 a Cislo2 vypočítá Vysledek:

public void Vypocitej()
{
        switch (Operace)
        {
                case "+":
                        Vysledek = Cislo1 + Cislo2;
                        break;
                case "-":
                        Vysledek = Cislo1 - Cislo2;
                        break;
                case "*":
                        Vysledek = Cislo1 * Cislo2;
                        break;
                case "/":
                        Vysledek = Cislo1 / Cislo2;
                        break;
        }
}

Výsledek se po zavolání metody uloží do vlastnosti Vysledek. Stejně tak bychom ho mohli i vrátit, jako jsme to dělali v minulém projektu s náhodným číslem. Pro naše další záměry s bindingem to ale bude takto výhodnější.

Model máme hotový, přidejme si kontroler.

Controller

Kontroler budeme mít v naší aplikaci zas jen jeden. Určitě si vzpomínáte, že kontroler slouží k propojení modelu (logiky) a pohledu (HTML šablony). Přidáme nový Empty Controller a pojmenujeme ho HomeController. Tím se spustí při vstupu na výchozí stránku aplikace. Přejděme do jeho kódu a metodu Index() upravme do následující podoby:

public IActionResult Index()
{
        Kalkulacka kalkulacka = new Kalkulacka();
        return View(kalkulacka);
}

Při vstupu na stránku se zavolá metoda Index(), to již víme. Tehdy vytvoříme novou instanci modelu, což je stále stejné, jako minule. Nově však model předáme pohledu jako parametr. Opět nezapomeňte nakliknout using MVCKalkulacka.Models.

View

Pro akci Index() vygenerujeme pohled. To uděláme opět kliknutím kamkoli do metody pravým tlačítkem a zvolením Add View. Jako Template zvolíme Create a Model class nastavíme na Kalkulacka.

Scaffolding v ASP.NET Core MVC

Template nám umožňuje do pohledu rovnou předgenerovat nějaký kód, této technice se říká scaffolding. Template Create vygeneruje pohled napojený na zvolený model a k vlastnostem tohoto modelu vygeneruje formulář pro vytvoření instance modelu. Když aplikaci nyní spustíme, vypadá takto:

https://local­host:44337
https://local­host:44337

Vidíme, že Visual Studio vygenerovalo celkem 4 inputy pro čísla, výsledek a operaci. Operaci však budeme chtít zadávat pomocí elementu <select> a výsledek nebudeme vypisovat do formulářového pole, ale do HTML odstavce <p>.

Přesuneme se proto do Index.cshtml a změníme ho do následující podoby:

@model MVCKalkulacka.Models.Kalkulacka

@{
    ViewData["Title"] = "Kalkulačka";
}

<head>
    <title>@ViewData["Title"]</title>
</head>

<body>
<h2>Index</h2>

<h4>Kalkulacka</h4>
<hr />
<div class="row">
    <div class="col-md-4">
                <form asp-action="Index">
                        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
                        <div class="form-group">
                                <label asp-for="Cislo1" class="control-label"></label>
                                <br />
                                <input asp-for="Cislo1" class="form-control" />
                                <span asp-validation-for="Cislo1" class="text-danger"></span>
                        </div>
                        <div class="form-group">
                                <label asp-for="Cislo2" class="control-label"></label>
                                <br />
                                <input asp-for="Cislo2" class="form-control" />
                                <span asp-validation-for="Cislo2" class="text-danger"></span>
                        </div>
                        <div class="form-group">
                                <label asp-for="Operace" class="control-label"></label>
                                <br />
                                @Html.DropDownListFor(model => model.Operace, new SelectList(Model.MozneOperace, "Value", "Text"))
                                <span asp-validation-for="Operace" class="text-danger"></span>
                        </div>
                        <div class="form-group">
                                <input type="submit" value="Vypočítej" class="btn btn-default" />
                        </div>

                        <p style="font-size: 2em;">@Model.Vysledek</p>

                </form>
    </div>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
</body>

Změn jsme proti původní podobě šablony provedli minimum. Na úplném začátku šablony vidíme nastavení typu modelu, na který je pohled nabindovaný (navázaný). Dále jsme nastavili titulek stránky a podnadpis. Všimněte si, že jelikož šablonu nevkládáme do layoutu, přidali jsme do ní elementy <head> a <body>. Následuje formulář, který vygenerovalo Visual Studio a pouze jsme ho upravili.

Jednotlivá editační pole pro vlastnosti modelu vkládáme tímto stylem:

<div class="form-group">
        <label asp-for="NazevVlastnosti" class="control-label"></label>
        <br />
        <input asp-for="NazevVlastnosti" class="form-control" />
        <span asp-validation-for="NazevVlastnosti" class="text-danger"></span>
</div>

Atributy asp-for jsou tzv. tag helpers, pomocí kterých dokáže ASP.NET Core vygenerovat pro naši vlastnost vhodný ovládací prvek. Např. pro datum se vloží DatePicker a podobně. Atributy asp-validation-for vloží prostor pro výpis chybové hlášky v případě, že uživatel pole špatně vyplní. To se opět zjistí z datového typu vlastnosti a vše tedy funguje zcela automaticky. Drobnou nevýhodou je, že danou vlastnost předáváme helperu jako text, což jste si jistě všimli. Visual Studio nám naštěstí správnost kódu dokáže zkontrolovat i tak.

Můžete vidět, že kombinujeme tag helpers se starším systémem vkládání ovládacích prvků pomocí IHtmlHelper (@Html). Ne všechny ovládací prvky jsou totiž v současnosti tag helpery podporovány, někdy se tomuto řešení nevyhneme. Preferujeme ovšem napojování formulářových prvků na vlastnosti modelu pomocí tag helperů a asp-for než pomocí zavináčů. Přeci chceme, aby HTML šablona vypadala co nejvíce jako HTML kód :)

Aby vám tag helpers v projektu fungovaly, je zapotřebí mít v něm i soubor pojmenovaný _ViewImports.cshtml s následujícím obsahem. Pokud jste postupovali podle tutoriálu, soubor již máte v projektu obsažený. Jestli jste si tento soubor omylem smazali nebo jste začali s prázdným projektem, můžete si jej nyní vytvořit:

@using MVCKalkulacka
@using MVCKalkulacka.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Na konci stránky vypíšeme vlastnost Vysledek modelu do HTML odstavce <p>, tím ho zobrazíme uživateli.

Náš formulář nyní vypadá takto:

MVC kalkulačka v ASP.NET Core

Po jeho odeslání se zatím nic nestane. Pokračovat budeme zas až příště.

V příští lekci, Zpracování dat a validace v ASP.NET Core MVC, aplikaci dokončíme. Pokud jste někde udělali chybu, v příští lekci si můžete také stáhnout kompletní kód projektu.


 

 

Článek pro vás napsal Martin Petrovaj
Avatar
Jak se ti líbí článek?
1 hlasů
Autor je lenivý vymýšľať nejaký slušný podpis. Venuje sa ale prevažne C#.
Aktivity (5)

 

 

Komentáře

Avatar
hricov.martin:27. června 13:47

Dobrý deň,chcel by som sa opýtať čo znamená v tomto príkaze public int Cislo1 { get; set; } get a set?

 
Odpovědět 27. června 13:47
Avatar
Martin Petrovaj
Překladatel
Avatar
Odpovídá na hricov.martin
Martin Petrovaj:27. června 14:36

Ahoj, jedná sa o tzv. vlastnosť - viac sa o nich dočítaš v OOP kurze: https://www.itnetwork.cz/…tery-settery

Get a set označujú tzv. gettery a settery, čiže metódy, pomocou ktorých navonok sprístupňujeme chránené premenné objektu. V iných jazykoch, napr. C++ či Java, sa naozaj musia zapisovať ako bežné metódy:

public class BankoveKonto
{

        private int stavKonta;

        public int getStavKonta()
        {
                return stavKonta;
        }

        public void setStavKonta(int novaHodnota)
        {
                if (novaHodnota >= 0) { stavKonta = novaHodnota; }
                else { /* vyhoď chybu */ }
        }

}

Následné použitie niekde inde v kóde (len príklad, dalo by sa to implementovať samozrejme aj inak):

private BankoveKonto ucet;
//...

public void vyberPenize(int suma)
{
        try { ucet.setStavKonta( ucet.getStavKonta() - suma ); }
        catch { /* upozorni uživatele */ }
}

C# nám uľahčuje život tým, že nemusíme už písať celé metódy, ale gettery / settery vytvoríme ako tzv. vlastnosti. Ekvivalentom vyššie uvedenej triedy BankoveKonto s vlastnosťami by bol nejaký takýto kód:

public class BankoveKonto
{
        private int stavKonta;
        public int StavKonta
        {
                get { return stavKonta; }
                set
                {
                        if (value >= 0) { stavKonta = value; }
                        else { /* chyba */ }
                }
        }
}

// ...

public void vyberPenize(int suma)
{
        try { ucet.StavKonta -= suma; } // alebo ucet.StavKonta = ucet.StavKonta - suma;
        catch {  }
}

Vidíme, že už sa nemusíme trápiť s nejakými metódami a so StavKonta môžeme navonok pracovať, ako keby to bola obyčajná premenná.

Novšie verzie C# to posúvajú ešte trochu ďalej a umožňujú aj používanie tzv. auto-implemented properties (niečo ako "automaticky implementované vlastnosti"). Tie zápis getteru / setteru ešte viac skracujú, ak pre ne nepotrebuješ žiadnu vlastnú logiku, ale ide ti napr. len o vytvorenie navonok readonly premennej:

public class BankoveKonto
{
        //...
        public string Iban { get; private set; } // táto premenná bude zvonku prístupná len na čítanie
}

Dúfam, že už to je trochu zrozumiteľnejšie, určite by si sa mal pozrieť aj na celý článok, na ktorý som sa na začiatku príspevku odkázal. Ak by ti niečo ešte nebolo jasné, kľudne sa pýtaj :-)

Odpovědět  +1 27. června 14:36
if (this.motto == "") { throw new NotImplementedException(); }
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na hricov.martin
David Čápka:27. června 14:47

Pokud nemáš načtený kurz OOP, tak je vážně nešťastný nápad číst takto pokročilé materiály.

Odpovědět  +4 27. června 14:47
Jsem moc rád, že jsi na síti, a přeji ti top IT kariéru, ať jako zaměstnanec nebo podnikatel. Máš na to! :)
Avatar
Jakub Ondrák:30. června 16:10

Hezky polopatě napsané a funguje :-) (kdybych nezapomněl v return View() parametr, tak by to fungovalo hned :-)

jen pro případné šťouraly by měl být case pro dělení následující, aby nebylo celočíselné:
case "/":
Vysledek = (double)Cislo1 / Cislo2;
break;

 
Odpovědět 30. června 16:10
Avatar
deli
Člen
Avatar
deli:25. července 20:43

Pri pokuse o spustenie aplikacie sa mi zobrazi nasledovny error:

 
Odpovědět 25. července 20:43
Avatar
David Čápka
Tým ITnetwork
Avatar
David Čápka:26. července 0:20

Pokud jste někde udělali chybu, v příští lekci si můžete také stáhnout kompletní kód projektu.

Odpovědět 26. července 0:20
Jsem moc rád, že jsi na síti, a přeji ti top IT kariéru, ať jako zaměstnanec nebo podnikatel. Máš na to! :)
Avatar
Adam Gajdečka:1. srpna 9:55

Podle mě tam máte chybu, mělo by se používat IActionResult, ne?

Proč je tady jen ActionResult, který se již v Core nepoužívá?

public ActionResult Index()
{
        Kalkulacka kalkulacka = new Kalkulacka();
        return View(kalkulacka);
}
 
Odpovědět 1. srpna 9:55
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Adam Gajdečka
David Čápka:2. srpna 18:28

Ahoj, díky, to byl překlep :) Opraveno.

Odpovědět 2. srpna 18:28
Jsem moc rád, že jsi na síti, a přeji ti top IT kariéru, ať jako zaměstnanec nebo podnikatel. Máš na to! :)
Avatar
Robert Hlavica:30. srpna 9:22

Ahoj chtěl jsem se zeptat jaký je rozdíl mezi

<input asp-for="Cislo1" class="form-control" />

a

@Html.TextBoxFor(model => model.Cislo2, new { htmlAttributes = new { @class = "form-control" } })

?

a druhá věc jak spravně nastavit input pro double tak aby v české lokalizaci vzal 1,5 a v anglickké 1.5?

Díky

 
Odpovědět 30. srpna 9:22
Avatar
Martin Petrovaj
Překladatel
Avatar
Odpovídá na Robert Hlavica
Martin Petrovaj:30. srpna 9:42

Input tag helper a @Html helpery TextBoxFor a EditorFor sa funčne v niektorých prípadoch prelínajú. Výhodou použitia tag helperu je ale už len to, že tento jeden tag helper môžeš používať namiesto hneď dvoch @Html helperov, a hlavne výsledná šablóna vyzerá viac ako HTML kód a menej ako zmiešanina HTML s C# :-) Pre teba to možno až taký problém nie je, ale v okamihu, keď pracuješ na jednom produkte s ďalšími ľuďmi, ktorí toľko nepoužívajú C#, napr. web dizajnéri, frontenďáci atď. to môže celkom pomôcť.

https://docs.microsoft.com/…g-with-forms?…

Čo sa týka validácie desatinnej bodky a čiarky, to už je trochu zložitejšia téma (ktorá sa ale nevzťahuje len na Core). Ak ti stačí len vždy prijímať aj čiarku, aj bodku, máš možnosť jeden znak vždy vymeniť za iný (napr. nahradiť čiarku bodkou). Budeš sa ale musieť nejako zbaviť built-in validácie alebo ju obísť. Možno by šlo túto úpravu spraviť ešte pred odoslaním formulára aj na strane klienta pomocou Javascriptu, ale v tom sa až tak nevyznám :-) Ďalšia možnosť je napr. použiť svoj vlastný tag helper.

Určite skús najprv poriadne prehľadať Stack Overflow, MSDN a podobné stránky, stavím sa, že podobný problém tam už niekto riešil a nejaké použiteľné riešenie tam nájdeš. Skús napr. tu: https://stackoverflow.com/…737/10239417

Odpovědět 30. srpna 9:42
if (this.motto == "") { throw new NotImplementedException(); }
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 10.