Základy formulářů

Ukážeme si, jak JellyPot pracuje s formuláři. Podíváme se, jaké formulářové prvky podporuje. Zkusíme si také nějaký formulář vytvořit a data z něj odeslaná uložit do databáze.

Kompletní zdrojový kód příkladu najdete na https://github.com/JellyPot/tutorial/tree/02-01. Nebo máte-li nainstalovaný git, můžete ve své cvičné lokální složce JellyPot spustit příkaz
git init & git pull https://github.com/JellyPot/tutorial.git 02-01
(Jen si v takovém případě rozbalte jen samotný JellyPot bez boilerplate – to by vám pak git hlásil kolize.)

Formulářové controly jsou umístěny ve vlastním namespace. Proto jejich tagy začínají f:, na rozdíl od je: používaného u ostatních controlů systému JellyPot. Celý formulář se umísťuje do serverového tagu <form>. Ten se může ve stránce vyskytovat jen jedenkrát (vlastnost ASP.NET).

JellyPot podporuje dva typy formulářů – <f:CollectionForm><f:EmailForm>. My se nejprve podíváme na jednodušší <f:CollectionForm>, který slouží k uložení dat z formuláře do databáze. <f:EmailForm>, který navíc umí data poslat na zvolený email, si ukážeme v další kapitole.

Do <f:CollectionForm> se umísťují dvě šablony:

  • formTemplate – kód formuláře, který se zobrazí na stránce
  • sentTemplate – kód, který se zobrazí po odeslání formuláře

Pro práci s formulářovými poli můžeme ve formTemplate používat následující controly:

  • <f:input> – slouží k vygenerování <input type="text"/>
  • <f:textarea> – slouží k vygenerování <textarea>
  • <f:check> – slouží k vygenerování <input type="checkbox" />
  • <f:select> – slouží k vygenerování <select>
  • <f:hidden> – slouží k vygenerování <input type="hidden" /> – pole, jehož hodnota není zobrazena uživateli, obvykle se vyplňuje javascriptem
  • <f:const> – pole, které obsahuje buď předem danou neměnnou hodnotu, nebo systémovou hodnotu typu aktuální čas, IP adresa klienta, URL aktuální stránky, user-agent atp.
  • <f:sendbutton><input type="submit" /> – tlačítko pro odeslání formuláře

Kontaktní formulář

Vraťme se k našemu příkladu s blogem. Na stránku „O autorovi“ bychom chtěli přidat jednoduchý formulář pro poslání zprávy autorovi. Na konec stránky /cs/about.aspx vložíme tento kód:

...
<form method="post" runat="server">
    <f:CollectionForm runat="server" id="contact" targetCollection="message">
        <formTemplate>
            <label>Vaše jméno* <f:input runat="server"
                                        id="name"
                                        targetField="name" />
            </label>
            <label>Email*      <f:input runat="server"
                                        id="email"
                                        targetField="email" />
            </label>
            <label>Zpráva      <f:textarea runat="server"
                                           id="message"
                                           targetField="message" />
            </label>
            <f:sendButton runat="server" textValue="Odeslat" />
        </formTemplate>
        <sentTemplate>
            <p>Zpráva byla odeslána. Díky!</p>
        </sentTemplate>      
    </f:CollectionForm>
</form>
...

Atributem targetCollection controlu <f:CollectionForm> říkáme, že data z odeslaného formuláře chceme uložit do kolekce message. Jednotlivé formulářové prvky mají atributy targetField – ty říkají, do kterého pole určené kolekce se hodnota uloží. Atribut id je povinný, slouží k identifikaci formulářových prvků uvnitř systému JellyPot a také k vygenerování atributů name ve finálním HTML.

V našem příkladu tedy musíme do Site.config doplnit kolekci message a typ jejích prvků MessageItem:

...
<Vars>
    <Collection name="message" itemType="MessageItem" />
</Vars>
...
<Types>
    <Type name="MessageItem">
        <SimpleText name="name" />
        <SimpleText name="email" />
        <Text name="message" />
    </Type>
</Types>
...

Diskuze pod články

V atributu targetCollection controlu <f:collectionForm> lze použít i relativní cestu ke kolekci. Toho využijeme pro vytvoření diskuze pod články. Do Site.config doplníme typ BlogPostCommentItem a rozšíříme typ BlogPostItem:

...
<Types>
    <Type name="BlogPostCommentItem">
        <SimpleText name="email" />
        <SimpleText name="name" />
        <DateTime name="added" />
        <Text name="message" />
    </Type>
    <Type name="BlogPostItem">
        <SimpleText name="title" />
        <DateTime name="published" />
        <Text name="text" />
        <Collection name="comment" itemType="BlogPostCommentItem" />
    </Type>
</Types>
...

(Pozn.: Na pořadí typů v sekci Types nezáleží.)

Na konec /cs/blogpost.aspx před značku </je:content> ukončující obsah pro region main vložíme formulář:

<je:content runat="server" forRegion="main">
...
<form runat="server" method="post">
    <f:collectionForm runat="server" id="forumPost" targetCollection=".comment">
        <formTemplate>
            <label>Jméno*  <f:input runat="server"
                                    id="name"
                                    targetField="name" />
            </label>
            <label>Email*  <f:input runat="server"
                                    id="email"
                                    targetField="email" />
            </label>
            <label>Zpráva* <f:textarea runat="server"
                                       id="message"
                                       targetField="message" />
            </label>
            <f:const runat="server" constType="DateTime" id="added" targetField="added" />
            <f:sendButton runat="server" textValue="Odeslat" />
        </formTemplate>
        <sentTemplate>
            <p>Přidáno!</p>
        </sentTemplate>      
    </f:collectionForm>
</form>
</je:content>

Tím máme zařízeno, že uživatelé můžou přidávat pod jednotlivé články komenty. Vložené komenty ale ještě musím pod článkem vypsat. To už ale umíme. V principu se to nijak neliší např. od vypsání přehledu článků na homepage. Kompletní kód stránky bude vypadat takto:

<%@ Page %>
<%@ Register TagPrefix="uc" TagName="teaser" Src="~/controls/teaser.ascx" %>

<je:container runat="server" expect="blogPost">
    <je:master runat="server" href="~/masters/main.master" />

    <je:content runat="server" forRegion="head">
        <title><je:item runat="server" field=".title" /></title>
    </je:content>

    <je:content runat="server" forRegion="main">
        <je:item runat="server" field=".title" tag="h1" />
        <je:item runat="server" field=".published" tag="time" />
        <je:avar runat="server" href="category.aspx" container=".category">
            <je:item runat="server" field=".category.title" />
        </je:avar>
        <je:item runat="server" field=".text" tag="p" />
        <h2>Diskuse</h2>
        <je:repeater runat="server" source=".comment">
            <item>
                <div class="comment">
                    <je:item runat="server" field=".name" tag="" />
                    <je:item runat="server" field=".added" tag="time" />
                    <je:item runat="server" field=".message" />
                </div>
            </item>
        </je:repeater>
        <h3>Přidejte příspěvek</h3>
        <form runat="server" method="post">
            <f:collectionForm runat="server" id="forumPost" targetCollection=".comment">
                <formTemplate>
                    <label>Jméno*  <f:input runat="server"
                                            id="name"
                                            targetField="name" />
                    </label>
                    <label>Email*  <f:input runat="server"
                                            id="email"
                                            targetField="email" />
                    </label>
                    <label>Zpráva* <f:textarea runat="server"
                                               id="message"
                                               targetField="message" />
                    </label>
                    <f:const runat="server" constType="DateTime" id="added" targetField="added" />
                    <f:sendButton runat="server" textValue="Odeslat" />
                </formTemplate>
                <sentTemplate>
                    <p>Přidáno!</p>
                </sentTemplate>      
            </f:collectionForm>
        </form>
    </je:content>
</je:container>

Připomínky a postřehy

Máte-li nějakou připomínku, dobrý nápad, něco není úplně pochopitelné nebo jste našli v tutoriálu chybu, rádi od vás uslyšíme.