2. diel - Blazor - Rozšírenie Todo aplikácie v .NET Core SPA
V minulej lekcii, Blazor - .NET Core SPA s C # .NET aj na strane klienta , sme si uviedli technológiu Blazor a vytvorili jednoduchú Todo aplikáciu.
V dnešnej lekcii si rozšírime úvodný príklad s Todo aplikáciou o
ďalší komponent TodoList
. Ukážeme si tiež, ako reagovať na
udalosti.
Model úlohy - Todo
Nová komponenta TodoList
bude zobrazovať zoznam úloh a ako
zdroj údajov teda bude mať kolekciu úloh. Pre úlohu, ktorý v našom
prípade obsahuje len text a informáciu o splnení, ešte nemáme vytvorenú
modelovú triedu. Poďme to teraz napraviť.
V Solution Exploreri vytvorme novú zložku Model/
a v nej novú
triedu s názvom Todo
. Do novej triedy pridáme dve vlastnosti:
public class Todo { public string Text { get; set; } public bool Done { get; set; } }
Nový menný priestor Model
tiež "zaregistrujte" v súbore
_Imports.razor
. To nám uľahčí prácu s našou novou triedou
vnútri komponentov:
@using BlazorITnetwork.Model
Váš menný priestor, teda časť BlazorITnetwork
,
sa samozrejme môže vymenovať inak v závislosti na názve projektu.
Komponent TodoList
V priečinku Shared/
vytvorme nový komponent
TodoList
. Ako som už spomenul vyššie, tento komponent bude
zobrazovať zoznam úloh, preto jej pridajme parameter typu
IList<Todo>
. Zoznam úloh zobrazíme s pomocou cyklu
foreach
as využitím Bootstrap ho
môžeme obaliť trebárs do .card
:
<div class="card"> <div class="card-header"> <h4 class="card-title">Seznam úkolů</h4> </div> <div class="card-body"> @if (Todos.Count == 0) { <span>Seznam je prázdný ...</span> } else { foreach (var todo in Todos) { <TodoItem Text="@todo.Text" Done="@todo.Done" /> } } </div> </div>
@code { [Parameter] public IList<Todo> Todos { get; set; } = new List<Todo>(); }
Ak vám Visual Studio
neochvejne tvrdí, že triedu Todo
nepozná, skúste
rebuild aplikácie. Prípadne skontrolujte vyššie popísanú
úpravu v súbore _Imports.razor
.
V súbore Index.razor
teraz zobrazíme nový komponent
TodoList
. Ako parameter ju odovzdáme zoznam úloh na zobrazenie.
Ten by sme v reálnej aplikácii pravdepodobne načítali z databázy, ale my si ho tu jednoducho vytvoríme
priamo v kóde:
<TodoList Todos="@todos"/>
@code{ IList<Todo> todos = new List<Todo>() { new Todo() {Text = "Naučit se Blazor na ITnetwork"}, new Todo() {Text = "Vytvořit vlastní Blazor aplikaci"}, new Todo() {Text = "Pochopit práci s parametry komponenty", Done = true} }; }
Ako vyzerá naše aplikácie po spustení je vidieť na nasledujúcom obrázku:
Pridanie novej úlohy
Rozšírime našu aplikáciu o ďalšiu funkcionalitu. Umožníme
užívateľovi pridať novú úlohu. K tomuto účelu vytvoríme komponentu
NewItemEntry.razor
. HTML časť komponenty sa bude skladať z:
- popisku,
- vstupného poľa pre text a
- tlačidlá pre spustenie akcie.
Pokiaľ bude vstupné pole prázdne, tlačidlo pre pridanie úlohy bude neaktívne. Komponent opäť môžeme naformátovať s pomocou Bootstrap. Časť s kódom bude zatiaľ obsahovať textovú vlastnosť pre nadviazanie na vstupné pole a vlastnosť iba na čítanie, ktorá zneprístupní tlačidlo, ak bude vstupné pole prázdne:
<div class="input-group input-group-lg"> <div class="input-group-prepend"> <span class="input-group-text">Nový úkol</span> </div> <input type="text" class="form-control" @bind="Text"/> <div class="input-group-append"> <button class="btn btn-secondary" disabled=@buttonDisabled>Přidat</button> </div> </div>
@code { public string Text { get; set; } string buttonDisabled => string.IsNullOrEmpty(Text) ? "disabled" : null; }
Komponent NewItemEntry
si vložíme do komponenty
TodoList
pod zoznam úloh:
...
<NewItemEntry/>
...
Výsledok vyzerá nejako takto:
Neaktívne polia
Než pridáme obsluhu stlačení tlačidla, poďme odstrániť na prvý pohľad nezistiteľnú chybu. Naša tlačidlo má byť neaktívne, pretože vstupné pole je prázdne, to je v poriadku. Ovšem ak do vstupného poľa napíšeme nejaký text, tlačidlo zostáva stále neaktívne a to už v poriadku nie je. Použili sme obojsmerný binding, tak kde je problém?
Tlačidlo sa aktivuje až vo chvíli, keď neprázdne pole opustíme (stratí
focus), napríklad kliknutím na inú komponent. Dôvodom je, že binding
defaultne reaguje na udalosť onchange
, ktorá sa vyvolá až pri
opustení vstupného poľa. My by sme potrebovali reagovať hneď po stlačení
klávesy, takže upravíme udalosť binding na oninput
:
... <input type="text" class="form-control" @bind="Text" @bind:event="oninput"/> ...
Po spustení sa tlačidlo aktivuje hneď po napísaní prvého znaku.
Obsluha kliknutie na tlačidlo
V komponente NewItemEntry
nemôžeme pri kliknutí na tlačidlo
pridať položku do zoznamu, pretože tento komponent zoznam úloh nemá. Zoznam
je v nadradenej komponente TodoList
, preto komponenta
NewItemEntry
iba "oznámi" nadradené komponente, že došlo k
stlačeniu tlačidla a poskytne jej text zo vstupného poľa. Výsledné
spracovanie tejto "udalosti" teda prebehne v komponente
TodoList
.
Do komponenty NewItemEntry
pridáme parameter
OnNewItem
typu EventCallback<string>
a túto
udalosť vyvoláme v novej metóde NewItem()
, ktorú zavoláme na
stlačenie tlačidla:
... <button class="btn btn-secondary @buttonDisabled" @onclick="NewItem">Přidat</button> ...
@code { ... [Parameter] public EventCallback<string> OnNewItem { get; set; } void NewItem() { OnNewItem.InvokeAsync(Text); Text = string.Empty; } }
Namiesto typu EventCallback<>
by sme mohli
použiť aj kľúčové slová event
a delegate
alebo
typy Action<>
, resp. Func<>
.
EventCallback
je však typ delegáta používaný na vystavenie
udalostí naprieč komponentmi. A nadradená komponenta môže samozrejme
priradiť obsluhu udalosti EventCallback
podriadené komponenty.
Pri použití udalosti EventCallback
týmto spôsobom sú
nadradené a podriadené komponenty automaticky prekreslené pri vyvolaní
udalosti. Pri ostatných vyššie spomenutých spôsobov by bolo nutné pre
správne prekreslenie volať metódu StateHasChanged()
.
Do komponenty TodoList
pridáme metódu OnNewItem()
s parametrom typu string
. Túto metódu použijeme pre obslúženie
našej novej udalosti na komponente NewItemEntry
. Len v nej
pridáme nový úlohu s odovzdaným textom do zoznamu úloh:
... <NewItemEntry OnNewItem="@OnNewItem"/> ...
@code { ... void OnNewItem(string text) { Todos.Add(new Todo() { Text = text }); } }
Všetko funguje, ako má:-) :
Reakcia na Enter
Komponent NewItemEntry
môžeme upraviť tak, aby okrem
stlačení tlačidla vyvolala akciu pridanie úlohy tiež po stlačení klávesy
Enter. Pokojne si to skúste najskôr sami;-)
Jedno z možných riešení je nižšie:
... <input type="text" class="form-control" @bind="Text" @bind:event="oninput" @onkeypress="KeyPress"/> ...
@code { ... void KeyPress(KeyboardEventArgs e) { if (e.Key == "Enter" && !string.IsNullOrEmpty(Text)) NewItem(); } }
To je pre dnešné lekciu všetko. Ak si chcete precvičovať, skúste treba
upraviť komponent TodoList
tak, aby sa po splnení všetkých
úloh sfarbilo záhlaví zelenou farbou.
V ďalšej lekcii, Blazor - Binding , sa pozrieme trochu hlbšie na one-way a two-way binding.