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.

sint ut eos exercitationem sed fugiat consequuntur non. adipisci dolor exercitationem occaecati rerum nisi quas molestias perferendis amet dolor natus sint vero odio deleniti. corporis nulla similique