Skip to content

5. Zarządzanie interfejsem użytkownika

5.1. Introduction

W relacji klient-serwer w sieci WWW klient przesyła informacje do serwera w postaci ciągu parametrów [param1=val1&param2=val2&...]. W naszych poprzednich przykładach najczęściej tworzyliśmy ten ciąg ręcznie, wysyłając adresy URL w postaci [http://localhost/appli? param1=val1&param2=val2&...]. W rzeczywistości informacje przekazywane przez klienta do serwera pochodzą z formularzy wypełnionych przez użytkownika. W niniejszym rozdziale omówimy sposób ich tworzenia. Przedstawimy również narzędzie WebMatrix, które pozwoli nam projektować interfejsy użytkownika. Sposób instalacji tego narzędzia opisano w załącznikach.

5.2. Język HTML

5.2.1. Przykład

Rozważmy następujący przykład, utworzony za pomocą narzędzia [Web Matrix], który przedstawia:

  • tabelę
  • obraz
  • link

Image

Uruchommy [WebMatrix], a następnie wybierzmy opcję [File/New File]:

Image

Decydujemy się utworzyć stronę o nazwie HTML. Powyższe informacje spowodują utworzenie pliku [d:\data\devel\aspnet\chap4\exemple1\exemple1.htm]. [WebMatrix] oferuje dwie możliwości edycji tego pliku: tryb [Design] oraz tryb [HTML]:

Image

Tryb [Design] umożliwia korzystanie z palety komponentów HTML oferowanej przez [WebMatrix]:

Image

Aby wstawić element z tej palety, wystarczy dwukrotnie na niego kliknąć, a następnie umieścić go w oknie [Design]. Tryb [HTML] umożliwia tworzenie dokumentu HTML za pomocą edytora tekstu. W tym celu należy znać składnię języka HTML. W zakładce [HTML] wygenerowano szkielet dokumentu:

Image

Okno [HTML] jest bardzo przydatne dla osób, które nie znają języka HTML. W oknie [Design] tworzy dokument i sprawdza kod HTML wygenerowany w oknie [HTML]. W ten sposób stopniowo opanowuje język HTML i dość szybko może pracować wyłącznie z edytorem tekstu, bez pomocy trybu [Design]. Pokażemy teraz, jak stworzyć dokument HTML przedstawiony na początku tej sekcji. Pracujemy w oknie [Design]. Najpierw wpisujemy bezpośrednio pierwszy wiersz tekstu:

Image

  • dodajemy komponent [Horizontal Rule] z palety komponentów:

Image

  • dodajemy komponent [Table]:

Image

  • umieszczamy kursor w trzecim wierszu tabeli, aby usunąć go za pomocą opcji [HTML/Edit Table/Delete Table Row]. Następnie wpisujemy oczekiwany tekst w każdej komórce:

Image

  • umieszczamy kursor w jednej z komórek tabeli i sprawdzamy jej właściwości. Okno właściwości wyświetla się w prawym dolnym rogu środowiska pracy:

Image

  • komórka jest reprezentowana przez tag HTML <TD>. Wyświetlane są zatem właściwości tagu <TD>. Skupiamy się na tabeli, która jest obiektem obejmującym komórkę. Klikamy na listę rozwijaną (click to see parent HTML elements) powyżej, aby wybrać obiekt <TABLE>:

Image

  • Obiekt <TABLE> posiada właściwość [border], która określa szerokość obramowania otaczającego komórki tabeli. W tym przypadku przyjmujemy wartość border=1.

Image

  • teraz edytujemy atrybuty obiektu <TD> komórki (1,2), aby ustawić align=Center i width=200 (pikseli). Tekst zostanie wyśrodkowany w komórce (align=center), a jej szerokość wyniesie 200 pikseli. Aby zobaczyć zmianę, czasami konieczne może być wybranie zakładki [HTML], a następnie powrót do zakładki [Design]:

Image

  • teraz umieszczamy tekst poprzedzający obraz:

Image

  • a następnie obraz, klikając dwukrotnie komponent [image] z palety:

Image

  • Zaznaczamy obraz, aby edytować jego właściwości:

Image

  • w atrybucie [src] wpisujemy nazwę pliku zawierającego obraz, w tym przypadku [univ01.gif]:

Image

  • umieszczamy tekst poprzedzający link:

Image

  • tworzymy z tekstu [ici] link do adresu URL [http://istia.univ-angers.fr]. W tym celu zaznaczamy go, a następnie wybieramy opcję [HTML/Insert Hyperlink]:

Image

  • otrzymujemy następujący wynik:

Image

  • już prawie gotowe. Przyjrzyjmy się kodowi HTML wygenerowanemu w zakładce [HTML]:
<html>
<head>
</head>
<body>
    <p>
        Le langage HTML - 1 
    </p>
    <hr />
    <table border="1">
        <tbody>
            <tr>
                <td>
                    cellule(1,1)</td>
                <td align="middle" width="200">
                    cellule(1,2)</td>
                <td>
                    cellule(1,3)</td>
            </tr>
            <tr>
                <td>
                    cellule(2,1)</td>
                <td>
                    cellule(2,2)</td>
                <td>
                    cellule(2,3)</td>
            </tr>
        </tbody>
    </table>
    <p>
        Une image <img src="univ01.gif" /> 
    </p>
    <p>
        Le site de l'istia <a href="http://istia.univ-angers.fr">ici</a>
    </p>
</body>
</html>

Pozostało nam jeszcze kilka szczegółów do dopracowania. Przede wszystkim chcielibyśmy nadać tytuł naszemu dokumentowi. [WebMatrix] nie pozwala na to w trybie [Design]. W zakładce [HTML] zastępujemy sekwencję <head>..</head> następującą sekwencją:

<head>
    <title>HTML1</title>
</head>

Ponadto chcielibyśmy, aby tekst [Le langage HTML - 1] był wyświetlany większą czcionką. Sekwencja <Hi>tekst</Hi> pozwala ustawić rozmiar tekstu, gdzie i przyjmuje wartości od 1 do 6, od największego do najmniejszego. W tym przypadku wybierzemy H2. Sekwencja

    <p>
        Le langage HTML - 1 
    </p>

przekształca się w:

<h2>Le langage HTML - 1</h2>

Okno [Design] odzwierciedla nasze zmiany:

Image

Pozostaje nam tylko przeprowadzić test przy użyciu opcji [View/Start] lub [F5]. Opcja [WebMatrix] wymaga podania kilku informacji w celu uruchomienia serwera WWW [Cassini]:

Image

Możemy zaakceptować wartości domyślne. Serwer [Cassini] zostaje uruchomiony, a nasza strona wyświetla się w przeglądarce:

Image

Z ciekawości możemy sprawdzić, z jakimi parametrami uruchomiono serwer [Cassini]:

Image

Przedstawiliśmy podstawy tworzenia strony HTML za pomocą [WebMatrix]. Zachęcamy czytelnika do tworzenia kolejnych stron HTML i sprawdzania za każdym razem wygenerowanego kodu HTML. Stopniowo będzie w stanie stworzyć stronę bez pomocy trybu [Design]. Dokument HTML ma następującą ogólną postać:

<html>
    <head>
        <title>Un titre</title>
        ...
    </head>
    <body attributs>
        ...
    </body>
</html>

Cały dokument jest ujęty w tagi <html>...</html>. Składa się on z dwóch części:

<head>...</head>: jest to niewidoczna część dokumentu. Zawiera informacje dla przeglądarki, która wyświetli dokument. Często znajduje się w niej tag <title>...</title>, który określa tekst wyświetlany w pasku tytułu przeglądarki. Można tam również znaleźć inne tagi, w szczególności te definiujące słowa kluczowe dokumentu, wykorzystywane następnie przez wyszukiwarki. W tej części można również znaleźć skrypty, najczęściej napisane w języku JavaScript lub VBScript, które zostaną wykonane przez przeglądarkę.

<body atrybuty>...</body>: jest to część, która zostanie wyświetlona przez przeglądarkę. Tagi zawarte w tej części wskazują przeglądarce „pożądany” wygląd dokumentu. Każda przeglądarka interpretuje te tagi na swój sposób. W związku z tym dwie przeglądarki mogą wyświetlać ten sam dokument internetowy w różny sposób. Jest to zazwyczaj jeden z problemów, z którymi borykają się projektanci stron internetowych.

Kod HTML poprzedniego dokumentu wyglądał następująco:

<html>
<head>
    <title>HTML1</title>
</head>
<body>
    <h2>Le langage HTML - 1 
    </h2>
    <hr />
    <table border="1">
        <tbody>
            <tr>
                <td>
                    cellule(1,1)</td>
                <td align="middle" width="200">
                    cellule(1,2)</td>
                <td>
                    cellule(1,3)</td>
            </tr>
            <tr>
                <td>
                    cellule(2,1)</td>
                <td>
                    cellule(2,2)</td>
                <td>
                    cellule(2,3)</td>
            </tr>
        </tbody>
    </table>
    <p>
        Une image <img src="univ01.gif" /> 
    </p>
    <p>
        Le site de l'istia <a href="http://istia.univ-angers.fr">ici</a> 
    </p>
</body>
</html>
Element
tagów i przykładów HTML
titre du document
<title>HTML1</title>
HTML1 pojawi się w pasku tytułu przeglądarki wyświetlającej dokument
barre horizontale
<hr>: wyświetla poziomą kreskę
tableau
<atrybuty tabeli>....</table>: w celu zdefiniowania tabeli
<tr atrybuty>...</tr>: do zdefiniowania wiersza
<td atrybuty>...</td>: do zdefiniowania komórki
przykłady:
<table border="1">...</table>: atrybut border określa grubość obramowania tabeli
<td align="center" width="200">komórka(1,2)</td>: definiuje komórkę, której zawartością będzie cellule(1,2). Zawartość ta zostanie wyśrodkowana w poziomie (align="center"). Komórka będzie miała szerokość 200 pikseli (width="200")
image
<img src="univ01.gif" />: definiuje obraz, którego plik źródłowy znajduje się na serwerze internetowym pod nazwą univ01.gif (src="univ01.gif"). Link ten znajduje się w dokumencie internetowym uzyskanym za pomocą URL http://localhost/exemple1.htm. W związku z tym przeglądarka wyśle żądanie do serwera URL http://localhost/univ01.gif, aby pobrać obraz, do którego odwołuje się ten link.
lien
<a href="http://istia.univ-angers.fr">tutaj</a>: sprawia, że tekst ici służy jako link do strony URL http://istia.univ-angers.fr.

Na tym prostym przykładzie widać, że aby zbudować cały dokument, przeglądarka musi wysłać dwa żądania do serwera:

http://localhost/exemple1.htm, aby pobrać kod źródłowy HTML dokumentu

http://localhost/univ01.gif, aby pobrać obraz o nazwie univ01.gif

5.2.2. Tworzenie formularza

Formularz HTML ma na celu przedstawienie użytkownikowi strony służącej do wprowadzania informacji, analogicznej do formularzy spotykanych w systemie Windows. Formularz ten jest wysyłany do przeglądarki w postaci dokumentu HTML. Przeglądarka wyświetli formularz użytkownikowi, który go wypełni i zatwierdzi za pomocą odpowiedniego przycisku. Następnie przeglądarka prześle wprowadzone wartości do serwera w celu przetworzenia. Zauważymy, że nie przesyła ona do serwera całego formularza, a jedynie wprowadzone wartości. Poniższy przykład przedstawia formularz internetowy, który również został utworzony przy użyciu WebMatrix:

Image

Kod HTML wygenerowany przez [WebMatrix] wygląda następująco:


<html>
    <head>
        <title>Formulaire</title>
        <script language="javascript">
        function effacer(){
            alert("Vous avez cliqué sur le bouton [Effacer]");
        }
        </script>
    </head>
    <body>
        <p>
            Gestion d'un formulaire
        </p>
        <hr />
        <form name="formulaire" method="post">
            <table border="1">
                <tr>
                    <td>
                        Etes-vous marié(e)</td>
                    <td>
                        <p align="center">
                            <input type="radio" value="oui" name="rdMarie" />Oui 
                            <input type="radio" checked value="non" name="rdMarie" />Non
                        </p>
                    </td>
                </tr>
                <tr>
                    <td>
                        Cases à cocher
                    </td>
                    <td>
                        <p align="center">
                            <input type="checkbox" value="un" name="C1" />1
                            <input type="checkbox" checked value="deux" name="C2" />2
                            <input type="checkbox" value="trois" name="C3" />3
                        </p>
                    </td>
                </tr>
                <tr>
                    <td>
                        Champ de saisie</td>
                    <td>
                        <p align="center">
                            <input type="text" maxlength="30" value="qqs mots" name="txtSaisie" />
                        </p>
                    </td>
                </tr>
                <tr>
                    <td>
                        Mot de passe</td>
                    <td>
                        <p align="center">
                            <input type="password" maxlength="12" size="12" value="unMotDePasse" name="txtMdp" />
                        </p>
                    </td>
                </tr>
                <tr>
                    <td>
                        Boîte de saisie</td>
                    <td>
                        <p align="center">
                        </p>
                        <textarea name="areaSaisie">ligne1
ligne2</textarea>
                    </td>
                </tr>
                <tr>
                    <td>
                        ComboBox</td>
                    <td>
                        <p align="center">
                        </p>
                        <select name="cmbValeurs">
                            <option value="1">choix1</option>
                            <option value="2" selected>choix2</option>
                            <option value="3">choix3</option>
                        </select>
                    </td>
                </tr>
                <tr>
                    <td>
                        Liste à choix simple</td>
                    <td>
                        <p align="center">
                        </p>
                        <select size="3" name="lstSimple">
                            <option value="1" selected>liste1</option>
                            <option value="2">liste2</option>
                            <option value="3">liste3</option>
                            <option value="4">liste4</option>
                            <option value="5">liste5</option>
                        </select>
                    </td>
                </tr>
                <tr>
                    <td>
                        Liste à choix multiple</td>
                    <td>
                        <p align="center">
                        </p>
                        <select multiple size="3" name="lstMultiple">
                            <option value="1" selected>multiple1</option>
                            <option value="2">multiple2</option>
                            <option value="3" selected>multiple3</option>
                            <option value="4">multiple4</option>
                            <option value="5">multiple5</option>
                        </select>
                    </td>
                </tr>
                <tr>
                    <td>
                        Bouton simple</td>
                    <td>
                        <p align="center">
                            <input onclick="effacer()" type="button" value="Effacer" name="btnEffacer" />
                        </p>
                    </td>
                </tr>
                <tr>
                    <td>
                        Bouton submit</td>
                    <td>
                        <p align="center">
                            <input type="submit" value="Envoyer" name="btnEnvoyer" />
                        </p>
                    </td>
                </tr>
                <tr>
                    <td>
                        Bouton reset</td>
                    <td>
                        <p align="center">
                            <input type="reset" value="Rétablir" name="btnRetablir" runat="server" />
                        </p>
                    </td>
                </tr>
            </table>
            <input type="hidden" name="secret" value="uneValeur" />
        </form>
    </body>
</html>

Związek między kontrolą wizualną <--> znacznikiem HTML jest następujący:

Kontrola
tag HTML
formulaire
<form name="formularz" method="post">
champ de saisie
<input type="text" maxlength="30" value="kilka słów" name="txtSaisie" />
champ de saisie cachée
<input type="password" maxlength="12" size="12" value="unMotDePasse" name="txtMdp" />
champ de saisie multilignes
<textarea name="areaSaisie">wiersz1
wiersz 2</textarea>
boutons radio
<input type="radio" value="tak" name="rdMarie" />Tak
<input type="radio" checked value="nie" name="rdMarie" />Nie
cases à cocher
<input type="checkbox" value="jeden" name="C1" />1
<input type="checkbox" checked value="dwa" name="C2" />2
<input type="checkbox" value="trzy" name="C3" />3
Combo
<select name="cmbValeurs">
<option value="1">opcja1</option>
<option value="2" selected>opcja 2</option>
<option value="3">opcja3</option>
</select>
liste à sélection unique
<select size="3" name="lstSimple">
<option value="1" selected>lista1</option>
<option value="2">lista2</option>
<option value="3">lista3</option>
<option value="4">lista4</option>
<option value="5">lista5</option>
</select>
liste à sélection multiple
<select multiple size="3" name="lstMultiple">
<option value="1" selected>multiple1</option>
<option value="2">multiple2</option>
<option value="3" selected>multiple3</option>
<option value="4">multiple4</option>
<option value="5">multiple5</option>
</select>
champ caché
<input type="hidden" name="secret" value="uneValeur" />
bouton de type submit
<input type="submit" value="Wyślij" name="btnEnvoyer" />
bouton de type reset
<input type="reset" value="Przywróć" name="btnRetablir" runat="server" />
bouton de type button
<input onclick="effacer()" type="button" value="Usuń" name="btnEffacer" />

Przyjrzyjmy się tym różnym elementom sterującym.

5.2.2.1. Formularz

formulaire
<form name="formularz" method="post">
balise HTML
<form name="..." method="..." action="...">...</form>
attributs
name="frmexemple": nazwa formularza
method="..." : metoda używana przez przeglądarkę do wysyłania do serwera WWW wartości zebranych w formularzu
action="..." : adres, na który zostaną wysłane wartości zebrane w formularzu.
Formularz internetowy jest otoczony tagami <form>...</form>. Formularz może mieć nazwę (name="xx"). Dotyczy to wszystkich elementów kontrolnych, które można znaleźć w formularzu. Nazwa ta jest przydatna, jeśli dokument internetowy zawiera skrypty, które muszą odwoływać się do elementów formularza. Celem formularza jest zebranie informacji podanych przez użytkownika za pomocą klawiatury lub myszy oraz przesłanie ich do serwera internetowego o adresie URL. Którego? Tego, do którego odwołuje się atrybut action="URL". Jeśli ten atrybut nie występuje, informacje zostaną wysłane na serwer URL dokumentu, w którym znajduje się formularz. W jaki sposób klient sieciowy przekazuje informacje (zawarte w formularzu) do serwera internetowego? Omówiliśmy to szczegółowo. Może on skorzystać z dwóch różnych metod o nazwach POST i GET. Atrybut method="méthode", z metodą równą GET lub POST, w tagu <form> wskazuje przeglądarce metodę, jaką należy zastosować do wysłania informacji zebranych w formularzu do adresu URL określonego przez atrybut action="URL". Gdy atrybut method nie jest określony, domyślnie stosowana jest metoda GET.

5.2.2.2. Pole wprowadzania danych

Image

champ de saisie
<input type="text" maxlength="30" value="kilka słów" name="txtSaisie" />
<input type="password" maxlength="12" size="12" value="unMotDePasse" name="txtMdp" />
balise HTML
<input type="..." name="..." size=".." value="..">
Tag `input` służy do różnych elementów sterujących. To właśnie atrybut type pozwala odróżnić te różne elementy sterujące od siebie.
attributs
type="text": określa, że jest to pole wprowadzania danych
type="password": znaki w polu wprowadzania danych są zastępowane znakami *. Jest to jedyna różnica w stosunku do zwykłego pola wprowadzania danych. Ten typ elementu kontrolnego nadaje się do wprowadzania haseł.
size="12": liczba znaków widocznych w polu – nie uniemożliwia wprowadzenia większej liczby znaków
maxlength="30": ustala maksymalną liczbę znaków na 30 – przeglądarka jest odpowiedzialna za egzekwowanie tego atrybutu
name="txtSaisie": nazwa elementu kontrolnego
value="kilka słów": tekst, który zostanie wyświetlony w polu wprowadzania danych.

5.2.2.3. Pole wprowadzania wielowierszowe

Image

champ de saisie multilignes
<textarea name="areaSaisie">wiersz1
wiersz 2</textarea>
balise HTML
<textarea ...>tekst</textarea>
wyświetla wielowierszowe pole wprowadzania danych z tekstem domyślnym
attributs
rows="2": liczba wierszy
cols="'20" : liczba kolumn
name="areaSaisie": nazwa kontrolki

5.2.2.4. Przyciski opcji

Image

boutons radio
<input type="radio" value="tak" name="rdMarie" />Tak
<input type="radio" checked value="nie" name="rdMarie" />Nie
balise HTML
<input type="radio" attribut2="valeur2" ..../>tekst
wyświetla przycisk opcji z tekstem obok.
attributs
name="rdMarie": nazwa elementu sterującego. Przyciski opcji o tej samej nazwie tworzą grupę przycisków wykluczających się wzajemnie: można zaznaczyć tylko jeden z nich.
value="wartość": wartość przypisana do przycisku opcji. Nie należy mylić tej wartości z tekstem wyświetlanym obok przycisku opcji. Ten ostatni służy wyłącznie do wyświetlania.
checked: jeśli to słowo kluczowe jest obecne, przycisk opcji jest zaznaczony, w przeciwnym razie nie jest.

5.2.2.5. Pola wyboru

cases à cocher
<input type="checkbox" value="jeden" name="C1" />1
<input type="checkbox" checked value="dwa" name="C2" />2
<input type="checkbox" value="trzy" name="C3" />3

Image

balise HTML
<input type="checkbox" attribut2="valeur2" ..../>tekst
wyświetla pole wyboru z tekstem obok.
attributs
name="C1": nazwa elementu sterującego. Pola wyboru mogą, ale nie muszą mieć tę samą nazwę. Pola o tej samej nazwie tworzą grupę powiązanych pól.
value="wartość": wartość przypisana do pola wyboru. Nie należy mylić tej wartości z tekstem wyświetlanym obok przycisku opcji. Ten ostatni służy wyłącznie do wyświetlania.
checked: jeśli to słowo kluczowe występuje, przycisk opcji jest zaznaczony, w przeciwnym razie nie jest.

5.2.2.6. Lista rozwijana (combo)

Combo
<select name="cmbValeurs">
<option value="1">opcja1</option>
<option value="2" selected>opcja 2</option>
<option value="3">opcja 3</option>
</select>

Image

balise HTML
<select size=".." name="..">
<option [selected="selected"] [value="valeur"]>tekst</option>
...
</select>
wyświetla na liście teksty zawarte między tagami <option>...</option>
attributs
name="cmbValeurs": nazwa kontrolki.
size="1": liczba widocznych elementów listy. size="1" sprawia, że lista działa jak pole kombi. Jest to wartość domyślna, jeśli brakuje atrybutu [size].
selected="selected": jeśli ten atrybut występuje w elemencie listy, element ten pojawia się jako zaznaczony na liście. W naszym powyższym przykładzie element listy choix2 pojawia się jako zaznaczony element listy rozwijanej, gdy jest ona wyświetlana po raz pierwszy.
value="wartość": określa wartość, która ma zostać wysłana do serwera w przypadku zaznaczenia elementu. Jeśli ten atrybut nie występuje, do serwera wysyłany jest tekst powiązany z opcją.

5.2.2.7. Lista z jednym wyborem

liste à sélection unique
<select size="3" name="lstSimple">
<option value="1" selected>lista1</option>
<option value="2">lista2</option>
<option value="3">lista3</option>
<option value="4">lista4</option>
<option value="5">lista5</option>
</select>

Image

balise HTML
<select size=".." name="..">
<option [selected] [value="valeur"]>...</option>
...
</select>
wyświetla na liście teksty zawarte między znacznikami <option>...</option>
attributs
takie same jak w przypadku listy rozwijanej wyświetlającej tylko jeden element. Ten element sterujący różni się od poprzedniej listy rozwijanej jedynie atrybutem size>1.

5.2.2.8. Lista z możliwością wielokrotnego wyboru

liste à sélection multiple
<select multiple size="3" name="lstMultiple">
<option value="1" selected>multiple1</option>
<option value="2">multiple2</option>
<option value="3" selected>multiple3</option>
<option value="4">multiple4</option>
<option value="5">multiple5</option>
</select>

Image

balise HTML
<select size=".." name=".." multiple>
<option [selected] ] [value="valeur"]>...</option>
...
</select>
wyświetla na liście teksty zawarte między znacznikami <option>...</option>
attributs
multiple: umożliwia zaznaczenie wielu elementów z listy. W powyższym przykładzie zaznaczone są zarówno elementy liste1, jak i liste3.

5.2.2.9. Przycisk typu button

bouton de type button
<input onclick="effacer()" type="button" value="Usuń" name="btnEffacer" />

Image

balise HTML
<input type="button" value="..." name="..." onclick="effacer()" ....>
attributs
type="button": definiuje kontrolkę przycisku. Istnieją dwa inne typy przycisków: submit i reset.
value="Usuń": tekst wyświetlany na przycisku
onclick="funkcja()": pozwala zdefiniować funkcję, która ma zostać wykonana, gdy użytkownik kliknie przycisk. Funkcja ta jest częścią skryptów zdefiniowanych w wyświetlanym dokumencie internetowym. Powyższa składnia jest zgodna ze standardem javascript. Jeśli skrypty są napisane w języku VBScript, należy wpisać onclick="funkcja" bez nawiasów. Składnia pozostaje taka sama, jeśli do funkcji trzeba przekazać parametry: onclick="funkcja(val1, val2,...)"
W naszym przykładzie kliknięcie przycisku Effacer wywołuje następującą funkcję JavaScript effacer:

        <script language="javascript">
        function effacer(){
            alert("Vous avez cliqué sur le bouton [Effacer]");
        }
        </script>
Funkcja effacer wyświetla komunikat:

5.2.2.10. Przycisk typu „submit”

bouton de type submit
<input type="submit" value="Wyślij" name="btnEnvoyer" />

Image

balise HTML
<input type="submit" value="Wyślij" name="btnEnvoyer">
attributs
type="submit": definiuje przycisk jako przycisk wysyłający dane formularza do serwera internetowego. Gdy użytkownik kliknie ten przycisk, przeglądarka wyśle dane formularza do adresu URL zdefiniowanego w atrybucie action tagu <form> zgodnie z metodą określoną przez atrybut method tego samego tagu.
value="Wyślij": tekst wyświetlany na przycisku

5.2.2.11. Przycisk typu reset

bouton de type reset
<input type="reset" value="Przywróć" name="btnRetablir" runat="server" />

Image

balise HTML
<input type="reset" value="Przywróć" name=" btnRetablir ">
attributs
type="reset": definiuje przycisk jako przycisk resetowania formularza. Gdy użytkownik kliknie ten przycisk, przeglądarka przywróci formularz do stanu, w jakim go otrzymała.
value="Przywróć": tekst wyświetlany na przycisku

5.2.2.12. Pole ukryte

champ caché
<input type="hidden" name="secret" value="uneValeur" />
balise HTML
<input type="hidden" name="..." value="...">
attributs
type="hidden": określa, że jest to pole ukryte. Pole ukryte stanowi część formularza, ale nie jest widoczne dla użytkownika. Jeśli jednak użytkownik poprosiłby przeglądarkę o wyświetlenie kodu źródłowego, zobaczyłby tag <input type="hidden" value="..."> i tym samym wartość pola ukrytego.
value="uneValeur": wartość pola ukrytego.
Jaka jest zaleta pola ukrytego? Pozwala to serwerowi internetowemu na przechowywanie informacji w trakcie kolejnych żądań wysyłanych przez klienta. Rozważmy przykład aplikacji do zakupów internetowych. Klient kupuje pierwszy produkt o numerze art1 w ilości q1 na pierwszej stronie katalogu, a następnie przechodzi do kolejnej strony katalogu. Aby zapamiętać, że klient kupił q1 sztuk produktu art1, serwer może umieścić te dwie informacje w ukrytym polu formularza internetowego na nowej stronie. Na tej nowej stronie klient kupuje produkty o numerach q2 i art2. Gdy dane z tego drugiego formularza zostaną wysłane na serwer (submit), serwer otrzyma nie tylko informację (q2,art2), ale także (q1,art1), które również stanowią część formularza jako ukryte pola, których użytkownik nie może modyfikować. Serwer WWW umieści wówczas w nowym ukrytym polu informacje (q1,art1) oraz (q2,art2) i wyśle nową stronę katalogu. I tak dalej.

5.3. Przesyłanie wartości formularza z przeglądarki do serwera internetowego

Z poprzedniego rozdziału wiemy już, w jaki sposób klient przesyła informacje do serwera. Czyni to za pomocą:

  • żądania o postaci HTTP GET url?param1=va1&param2=val2&....
  • żądania o postaci HTT POST url, po którym następuje dokument zawierający ciąg parametrów param1=va1&param2=val2&....

Przeglądarka zastosuje jedną z tych dwóch metod w zależności od tego, czy atrybut [method] tagu [form] ma wartość GET czy POST. To właśnie teraz pokażemy. Strona omówiona wcześniej jest stroną statyczną. Aby uzyskać dostęp do nagłówków HTTP wysyłanych przez przeglądarkę, która zażąda tego dokumentu, przekształcamy ją w stronę dynamiczną dla serwera internetowego .NET (IIS lub Cassini). Poprzedni kod statyczny umieszczamy w pliku [formulaire_get.aspx], a jego zawartość jest następująca:


<%@ Page src="formulaire_get.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="formulaire_get" %>
<html>
    <head>
        <title>Formulaire</title>
        <script language="javascript">
        function effacer(){
            alert("Vous avez cliqué sur le bouton [Effacer]");
        }
        </script>
    </head>
    <body>
.....
    </body>
</html>

Powyższa strona prezentacyjna jest powiązana z kontrolerem [formulaire_get.aspx.vb]:


Public Class formulaire_get
    Inherits System.Web.UI.Page

    Private Sub Page_Init(ByVal Sender As Object, ByVal e As System.EventArgs) Handles MyBase.Init
        ' zapisuje bieżące zapytanie w request.txt w folderze strony
        Dim requestFileName As String = Me.MapPath(Me.TemplateSourceDirectory) + "\request.txt"
        Me.Request.SaveAs(requestFileName, True)
    End Sub
End Class

Przy każdym wywołaniu dokumentu [formulaire_get.aspx] żądanie klienta zostanie zapisane w pliku [request.txt] przez procedurę Page_Init. Z tym sposobem działania mieliśmy już do czynienia, dlatego nie będziemy dalej omawiać tego kontrolera.

5.3.1. Metoda GET

Przeprowadźmy pierwszy test, w którym w kodzie HTML dokumentu tag FORM jest zdefiniowany w następujący sposób:


        <form name="formulaire" method="get">

Umieszczamy pliki [formulaire_get.aspx] i [formulaire_get.aspx.vb] w folderze <application-path> i uruchamiamy serwer Cassini z parametrami (<application-path>,/form2). Wprowadzamy adres URL http://localhost/form2/formulaire_get.aspx:

Image

Przeglądarka właśnie wysłała żądanie i wiemy, że zostało ono zapisane w pliku [request.txt]. Przyjrzyjmy się jego zawartości:

GET /form2/formulaire_get.aspx HTTP/1.1
Cache-Control: max-age=0
Connection: keep-alive
Keep-Alive: 300
Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0.1
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Accept-Encoding: gzip,deflate
Accept-Language: en-us,en;q=0.5
Host: localhost
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040316

Przeglądarka użyła zapytania HTTP GET, aby uzyskać adres URL [http://localhost/form2/formulaire_get.aspx]. Dzieje się tak zawsze, gdy adres URL jest podawany przez użytkownika. Formularz wypełniamy w następujący sposób:

Image

Korzystamy z powyższego przycisku [Envoyer]. Jego kod HTML wygląda następująco:

<form method="get">
    ...
    <input type="submit" value="Envoyer">
    ...
</form>

Po kliknięciu przycisku typu [Submit] przeglądarka wysyła parametry formularza (tag <form>) do adresu URL wskazanego w atrybucie [action] tagu <form action="URL">, o ile taki istnieje. Jeśli ten atrybut nie istnieje, parametry formularza są wysyłane do adresu URL, z którego pochodzi formularz. Tak jest w tym przypadku. Przycisk [Envoyer] powinien zatem spowodować wysłanie przez przeglądarkę żądania do serwera URL [http://localhost/form2/formulaire_get.aspx] wraz z przekazaniem parametrów formularza. Ponieważ strona [formulaire_get.aspx] zapamiętuje otrzymane żądanie, powinniśmy wiedzieć, w jaki sposób klient przesłał te parametry. Spróbujmy. Klikamy przycisk [Envoyer]. Otrzymujemy następującą odpowiedź z przeglądarki:

Image

Jest to strona początkowa, ale można zauważyć, że wartość URL w polu [Adresse] przeglądarki uległa zmianie. Przybrała następującą postać:

http://localhost/form2/formulaire_get.aspx?rdMarie=tak&C1=jeden&C2=dwa&txtSaisie=programowanie+asp.net&txtMdp=unMotDePasse&areaSaisie=podstawy+programowania+0D%0Aprogramowanie+stron+internetowych%0D%0A&cmbValeurs=3&lstSimple=1&lstMultiple=2&lstMultiple=4&btnEnvoyer=Wyślij&secret=uneValeur

Widać, że wybory dokonane w formularzu znajdują się w polu URL. Przyjrzyjmy się zawartości pliku [request.txt], który zapisał żądanie klienta:

GET /form2/formulaire_get.aspx?rdMarie=oui&C1=un&C2=deux&txtSaisie=programmation+asp.net&txtMdp=ceciestsecre&areaSaisie=les+bases+de+la%0D%0Aprogrammation+web%0D%0A&cmbValeurs=3&lstSimple=1&lstMultiple=2&lstMultiple=4&btnEnvoyer=Envoyer&secret=uneValeur HTTP/1.1
Connection: keep-alive
Keep-Alive: 300
Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0,1
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Accept-Encoding: gzip,deflate
Accept-Language: en-us,en;q=0.5
Host: localhost
Referer: http://localhost/form2/formulaire_get.aspx
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040316

Widać zapytanie HTTP, dość podobne do tego, które pierwotnie wysłała przeglądarka, gdy żądała dokumentu bez przekazywania parametrów. Istnieją dwie różnice:

GET URL HTTP/1.1
Parametry formularza zostały dodane po adresie URL dokumentu w postaci ?param1=val1&param2=val2&...
Referer
Klient wskazuje za pomocą tego nagłówka HTTP numer URL dokumentu, który wyświetlał w momencie wysłania żądania

Przyjrzyjmy się bliżej, w jaki sposób parametry zostały przekazane w poleceniu GET URL?param1=wartość1&param2=wartość2&... HTTP/1.1, gdzie parami to nazwy elementów sterujących formularza internetowego, a valeuri to przypisane do nich wartości. Poniżej przedstawiamy tabelę z trzema kolumnami:

  • kolumna 1: zawiera definicję elementu sterującego HTML z przykładu
  • kolumna 2: przedstawia wygląd tego elementu w przeglądarce
  • kolumna 3: przedstawia wartość wysyłaną do serwera przez przeglądarkę dla elementu z kolumny 1 w postaci, jaką ma ona w zapytaniu GET z przykładu
element sterujący HTML
wygląd przed zatwierdzeniem
zwracana(-e) wartość(-i)
<input type="radio" value="tak" name="rdMarie" />Tak
<input type="radio" checked
value="nie" name="rdMarie" />Nie
rdMarie=tak
– wartość atrybutu value przycisku
zaznaczonego przez użytkownika.
<input type="checkbox"
value="un" name="C1" />1
<input type="checkbox"
checked value="deux" name="C2" />2
<input type="checkbox"
value="trzy" name="C3" />3
C1=jeden
C2=dwa
– wartości atrybutów value pól
zaznaczonych przez użytkownika
<input type="text" maxlength="30" value="qqs
słów" name="txtSaisie" />
txtSaisie=programowanie+asp.net
– tekst wpisany przez użytkownika w polu
wprowadzania danych. Spacje zostały zastąpione
znakiem +
<input type="password"
maxlength="12" size="12"
value="hasło"
name="txtMdp" />
txtMdp=tojesttajemnica
– tekst wpisany przez użytkownika w polu
wprowadzania danych. Tekst faktycznie wpisany brzmiał
„tojesttajemnica”. Ostatni znak został
utracony, ponieważ atrybut
maxlength="12" ograniczał liczbę
znaków do 12.
<textarea name="areaSaisie">
wiersz1
wiersz2</textarea>
poleWprowadź=podstawy+
%0D%0A
programowania+stron+internetowych
– tekst wpisany przez użytkownika w polu
wprowadzania danych. %OD%OA to znak
końca linii. Spacje zostały
zastąpione znakiem +
<select name="cmbValeurs">
<option value="1">opcja1
</option>
<option value="2" selected>opcja 2
</option>
<option value="3">opcja 3
</option>
</select>
cmbWartości=3
- wartość wybrana przez użytkownika z
liście z jedną opcją do wyboru
<select size="3"
name="lstSimple">
<option value="1"
selected>lista1</option>
<option value="2">lista2
</option>
<option value="3">lista3
</option>
<option value="4">lista4
</option>
<option value="5">lista5
</option>
</select>
lstSimple=3
- wartość wybrana przez użytkownika z
liście z jednym wyborem
<select multiple size="3"
name="lstMultiple">
<option value="1" selected>multiple1
</option>
<option value="2">multiple2
</option>
<option value="3" selected>multiple3
</option>
<option value="4">multiple4
</option>
<option value="5">multiple5
</option>
</select>
lstMultiple=2
lstMultiple=4
- wartości wybrane przez użytkownika z
liście z możliwością wielokrotnego wyboru
<input type="submit"
value="Wyślij"
name="btnEnvoyer" />
btnEnvoyer=Wyślij
– nazwa i atrybut value przycisku, który
służył do wysłania danych formularza
na serwer
<input type="hidden"
name="secret"
value="uneValeur" />
 
secret=uneValeur
– atrybut value pola ukrytego

Można się zastanawiać, co serwer zrobił z przekazanymi mu parametrami. W rzeczywistości nic. Po otrzymaniu polecenia

GET /form2/formulaire_get.aspx?rdMarie=oui&C1=un&C2=deux&txtSaisie=programmation+asp.net&txtMdp=ceciestsecre&areaSaisie=les+bases+de+la%0D%0Aprogrammation+web%0D%0A&cmbValeurs=3&lstSimple=1&lstMultiple=2&lstMultiple=4&btnEnvoyer=Envoyer&secret=uneValeur HTTP/1.1

serwer WWW przekazał parametry do pliku URL, [http://localhost/form2/formulaire_get.aspx] oraz c.a.d, czyli do dokumentu, który stworzyliśmy na początku. Nie napisaliśmy żadnego kodu do pobierania i przetwarzania parametrów przesyłanych przez klienta. Dlatego wszystko przebiega tak, jakby żądanie klienta brzmiało po prostu:

GET http://localhost/form2/formulaire_get.aspx

Z tego powodu w odpowiedzi na nasze wywołanie przycisku [Envoyer] otrzymaliśmy tę samą stronę, co początkowo przy wywołaniu URL i [http://localhost/form2/formulaire_get.aspx] bez parametrów.

5.3.2. Metoda POST

Dokument HTML jest teraz skonfigurowany tak, aby przeglądarka korzystała z metody POST do wysyłania wartości formularza na serwer WWW. W tym celu kopiujemy plik [formulaire_get.aspx] do pliku [formulaire_post.aspx] i modyfikujemy wyłącznie tag <form> w pliku [formulaire_post.aspx]:


<%@ Page src="formulaire_get.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="formulaire_get" %>
<html>
    <head>
        ...
    </head>
    <body>
        <p>
            Gestion d'un formulaire
        </p>
        <hr />
        <form name="formulaire" method="post">
            <table border="1">

Nie ma potrzeby zmiany kontrolera [formulaire_get.aspx.vb], więc pozostawiamy go bez zmian. Żądamy nowego dokumentu za pomocą URL [http://localhost/form2/formulaire_post.aspx], wypełniamy formularz tak samo jak w przypadku metody GET i przesyłamy parametry do serwera za pomocą przycisku [Envoyer]. Otrzymujemy z serwera następującą stronę odpowiedzi:

Image

Otrzymujemy zatem ten sam wynik, co w przypadku metod GET i c.a.d – stronę początkową. Warto zwrócić uwagę na jedną różnicę: w polu [Adresse] przeglądarki nie pojawiają się przesłane parametry. Przyjrzyjmy się teraz żądaniu wysłanemu przez klienta, które zostało zapisane w pliku [request.txt]:

POST /form2/formulaire_post.aspx HTTP/1.1
Connection: keep-alive
Keep-Alive: 300
Content-Length: 222
Content-Type: application/x-www-form-urlencoded
Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0,1
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Accept-Encoding: gzip,deflate
Accept-Language: en-us,en;q=0.5
Host: localhost
Referer: http://localhost/form2/formulaire_post.aspx
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040316

rdMarie=oui&C1=un&C2=deux&txtSaisie=programmation+asp.net&txtMdp=ceciestsecre&areaSaisie=les+bases+de+la%0D%0Aprogrammation+web%0D%0A&cmbValeurs=3&lstSimple=3&lstMultiple=2&lstMultiple=4&btnEnvoyer=Envoyer&secret=uneValeur

W zapytaniu klienta HTTP pojawiają się nowe pozycje:

POST URL HTTP/1.1
Zapytanie GET zostało zastąpione zapytaniem POST. Parametry nie występują już w pierwszym wierszu zapytania. Można zauważyć, że znajdują się one teraz za zapytaniem HTTP, po pustym wierszu. Ich kodowanie jest identyczne jak w zapytaniu GET.
Content-Length
liczba „wysłanych” znaków, c.a.d. Liczba znaków, które serwer WWW będzie musiał odczytać po otrzymaniu nagłówków HTTP, aby pobrać dokument wysłany przez klienta. Dokumentem tym jest w tym przypadku lista wartości z formularza.
Content-type
określa typ dokumentu, który klient wyśle po nagłówkach HTTP. Typ [application/x-www-form-urlencoded] wskazuje, że jest to dokument zawierający wartości z formularza.

Istnieją dwie metody przesyłania danych do serwera WWW: GET i POST. Czy jedna z tych metod jest lepsza od drugiej? Widzieliśmy, że jeśli wartości formularza były wysyłane przez przeglądarkę metodą GET, przeglądarka wyświetlała w polu Adresse żądaną wartość URL w postaci URL?param1=val1&param2=val2&.... Można to postrzegać jako zaletę lub wadę:

  • zaletą, jeśli chcemy umożliwić użytkownikowi dodanie tego skonfigurowanego adresu URL do ulubionych
  • wadą, jeśli nie chcemy, aby użytkownik miał dostęp do niektórych informacji zawartych w formularzu, takich jak na przykład pola ukryte

W dalszej części będziemy stosować w naszych formularzach niemal wyłącznie metodę POST.

5.4. Przetwarzanie wartości formularza po stronie serwera

5.4.1. Przedstawienie przykładu

Teraz, gdy ustaliliśmy związek między tagiem HTML <form method="GET/POST" ...> a sposobem, w jaki przeglądarka wysyła wartości formularza, wiemy już, jak pobrać je po stronie serwera. Odpowiedź znaleźliśmy w poprzednim rozdziale:

  • jeśli metodą tagu <form> jest GET, wartości parametrów zostaną pobrane z kolekcji [Request.QueryString]
  • jeśli metodą tagu <form> jest POST, wartości „wysłanych” parametrów zostaną pobrane z kolekcji [Request.Form]. Należy tu wprowadzić pewne wyjaśnienie. Tag <form> może określać za pomocą atrybutu [action] docelowy adres URL GET lub POST. Adres ten można z łatwością skonfigurować niezależnie od tego, czy mamy do czynienia z elementem GET, czy POST, w postaci action="url?param1=val1&param2=val2&..". Parametry te są następnie dodawane do tych zawartych między tagami <form> i </form>, które zostaną przesłane na serwer za pomocą GET lub POST. Ponieważ stanowią one część docelowego adresu URL, zostaną one pobrane z kolekcji [Request.QueryString], niezależnie od tego, czy mamy do czynienia z GET, czy z POST.

Teraz tworzymy aplikację MVC z dwoma widokami:

  • pierwszy widok to poprzedni formularz. Nazwiemy go [vue_formulaire].
  • Drugi widok to strona informacyjna zawierająca listę wartości wprowadzonych na pierwszej stronie. Link umożliwia powrót do formularza. Nazwiemy ten widok [vue_confirmation].

Widok [vue_formulaire] jest wysyłany do użytkownika, który go wypełnia i zatwierdza. Tuż przed zatwierdzeniem może wyglądać następująco:

Image

Użytkownik korzysta z przycisku [Envoyer], aby zatwierdzić wprowadzone dane. W odpowiedzi otrzymuje następujący widok [vue_validation]:

Image

5.4.2. Kontroler aplikacji

W poprzednim rozdziale widzieliśmy, że rolę kontrolera aplikacji MVC możemy powierzyć plikowi [global.asax], przez który przechodzą wszystkie żądania klientów. Przedstawiliśmy już aplikację MVC zbudowaną w ten sposób i w tym miejscu kierujemy się modelem programowania przedstawionym wówczas. Plik [global.asax] będzie wyglądał następująco:

<%@ Application src="Global.asax.vb" Inherits="Global" %>

Składa się on z jednego wiersza odwołującego się do kontrolera umieszczonego w pliku [global.asax.vb]:


Imports System
Imports System.Web
Imports System.Web.SessionState

Public Class Global
    Inherits System.Web.HttpApplication

    Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
        ' pobieramy akcję do wykonania
        Dim action As String
        If Request.QueryString("action") Is Nothing Then
            action = "init"
        Else
            action = Request.QueryString("action").ToString.ToLower
        End If
        ' wykonujemy akcję
        Select Case action
            Case "init"
                Server.Transfer("formulaire.aspx", False)
            Case "validation"
                Server.Transfer("validation.aspx", True)
            Case Else
                Server.Transfer("formulaire.aspx", True)
        End Select
    End Sub
End Class

Zasada działania kontrolera jest następująca:

  • kontroler oczekuje w docelowym adresie URL ciągu parametrów zawierającego parametr [action]. Jeśli ten parametr nie występuje, traktuje się to tak, jakby w ciągu parametrów znajdował się parametr [action=init].
  • Rozpoznawane są tylko dwie akcje:
    • init: wysyłamy do klienta wstępnie wypełniony formularz
    • validation: klient otrzymuje stronę potwierdzającą wprowadzone dane
  • jeśli akcja nie jest jedną z powyższych, traktuje się to tak, jakby w łańcuchu parametrów znajdował się parametr [action=init]. Można również wyświetlić stronę błędu.

5.4.3. Obsługa akcji „init”

Gdy kontroler przetwarza akcję „init”, musi wygenerować wstępnie wypełniony formularz. Zadaniem strony [formulaire.aspx] jest wykonanie tej czynności. Jej kod wygląda następująco:


<HTML>
    <HEAD>
        <title>Formulaire</title>
        <script language="javascript">
        function effacer(){
            alert("Vous avez cliqué sur le bouton [Effacer]");
        }
        function raz(liste){
            liste.selectedIndex=-1
        }
        </script>
    </HEAD>
    <body>
        <p>
            Gestion d'un formulaire
        </p>
        <hr>
        <form name="formulaire" method="post" action="?action=validation">
            <table border="1">
                <tr>
                    <td>
                        Etes-vous marié(e)</td>
                    <td>
                        <p align="center">
                            <input type="radio" value="oui" name="rdMarie">Oui <input type="radio" checked value="non" name="rdMarie">Non
                        </p>
                    </td>
                </tr>
....
                    <td>
                        <select size="3" name="lstSimple">
                            <option value="1" selected>liste1</option>
                            <option value="2">liste2</option>
                            <option value="3">liste3</option>
                            <option value="4">liste4</option>
                            <option value="5">liste5</option>
                        </select>
                        <INPUT type="button" value="Raz" name="btnRazSimple" onclick="raz(lstSimple)">
                    </td>
....
                    <td>
                        <select multiple size="3" name="lstMultiple">
                            <option value="1" selected>multiple1</option>
                            <option value="2">multiple2</option>
                            <option value="3" selected>multiple3</option>
                            <option value="4">multiple4</option>
                            <option value="5">multiple5</option>
                        </select>
                        <INPUT type="button" value="Raz" name="btnRazMultiple" onclick="raz(lstMultiple)">
                    </td>
...

            </table>
            <input type="hidden" name="secret" value="uneValeur">
        </form>
    </body>
</HTML>

Ponownie spotykamy kod HTML z omówionego wcześniej formularza, z kilkoma niewielkimi różnicami. Kod tagu <form> został zmieniony:


        <form name="formulaire" method="post" action="?action=validation">
  • post: wartości wprowadzone przez użytkownika, a następnie wysłane na serwer po naciśnięciu przycisku typu [submit], będą przesyłane metodą HTTP POST
  • akcja: składnia action="url" służy do określenia adresu URL, na który mają zostać wysłane wartości formularza. Adres ten może zawierać ciąg parametrów w postaci param1=val1&param2=val2&... Tak właśnie postępujemy w tym przypadku, przekazując parametr [action=validation], aby wskazać kontrolerowi, jaką akcję ma wykonać. Należy zauważyć, że ten ciąg parametrów nie jest poprzedzony adresem internetowym. Przeglądarka wyśle zatem parametry formularza na adres, z którego pochodzi ten formularz. W naszym przykładzie przedstawionym powyżej adres ten to [http://localhost/mvcform1]. Przeglądarka wyśle zatem żądanie [POST /mvcform1?action=validation] do serwera [localhost].

Dodano przyciski, aby umożliwić użytkownikowi odznaczenie elementów z list [lstSimple] i [lstMultiple]:

Image

Przekłada się to na następujący kod HTML:


                    <td>
                        <select size="3" name="lstSimple">
                            <option value="1" selected>liste1</option>
                            <option value="2">liste2</option>
                            <option value="3">liste3</option>
                            <option value="4">liste4</option>
                            <option value="5">liste5</option>
                        </select>
                        <INPUT type="button" value="Raz" name="btnRazSimple" onclick="raz(lstSimple)">
                    </td>
....
                    <td>
                        <select multiple size="3" name="lstMultiple">
                            <option value="1" selected>multiple1</option>
                            <option value="2">multiple2</option>
                            <option value="3" selected>multiple3</option>
                            <option value="4">multiple4</option>
                            <option value="5">multiple5</option>
                        </select>
                        <INPUT type="button" value="Raz" name="btnRazMultiple" onclick="raz(lstMultiple)">
                    </td>

Kliknięcie przycisku [Raz] powoduje odznaczenie wszystkich elementów listy, z którą jest powiązany. Weźmy na przykład listę [lstMultiple]. Kliknięcie odpowiedniego przycisku [Raz] powoduje wykonanie funkcji JavaScript [raz(lstMultiple)]. Należy pamiętać, że kod JavaScript dokumentu HTML wyświetlanego przez przeglądarkę jest wykonywany przez tę samą przeglądarkę, a nie przez serwer. JavaScript jest bardzo wszechstronnym językiem, który pozwala nadać stronom dynamiczny charakter bez udziału serwera. Funkcja [raz] wygląda następująco:

        function raz(liste){
            liste.selectedIndex=-1
        }

Funkcja ta przyjmuje parametr, którym jest obiekt JavaScript reprezentujący listę HTML. Obiekt ten posiada właściwości i metody. Jedną z jego właściwości jest [selectedIndex], której wartością jest numer pierwszej opcji wybranej z listy HTML. Jeśli nie ma żadnej opcji, wartość tej właściwości wynosi -1. Z drugiej strony, nadanie wartości tej właściwości powoduje wybranie nowego elementu z listy HTML, a nadanie jej wartości -1 oznacza, że żaden element nie jest zaznaczony. Właśnie to ma miejsce w tym przypadku.

Na koniec należy zauważyć, że kod prezentacji [formulaire.aspx] nie jest powiązany z kontrolerem [formulaire.aspx.vb]. W dokumencie HTML nie ma bowiem żadnej części dynamicznej generowanej przez serwer, więc nie ma potrzeby stosowania kontrolera.

5.4.4. Obsługa akcji „walidacja”

Gdy kontroler przetwarza akcję „walidacja”, musi wygenerować stronę zawierającą listę wartości wprowadzonych przez użytkownika. Zadaniem strony [validation.aspx] jest wykonanie tej czynności. Wizualnie strona wygląda następująco:

Image

Jej kod HTML wygląda następująco:


<%@ Page src="validation.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="validation" %>
<HTML>
    <HEAD>
        <title>validation</title>
    </HEAD>
    <body>
        <P>Valeurs saisies</P>
        <HR width="100%" SIZE="1">
        <TABLE id="Table1" cellSpacing="1" cellPadding="1" width="300" border="1">
            <TR>
                <TD width="84">rdMarie</TD>
                <TD><% =rdMarie%></TD>
            </TR>
            <TR>
                <TD width="84">C1</TD>
                <TD><%=C1%></TD>
            </TR>
            <TR>
                <TD width="84">C2</TD>
                <TD><%=C2%></TD>
            </TR>
            <TR>
                <TD width="84">C3</TD>
                <TD><%=C3%></TD>
            </TR>
            <TR>
                <TD width="84">txtSaisie</TD>
                <TD><%=txtSaisie%></TD>
            </TR>
            <TR>
                <TD width="84">txtMdp</TD>
                <TD><%=txtMdp%></TD>
            </TR>
            <TR>
                <TD width="84">areaSaisie</TD>
                <TD><%=areaSaisie%></TD>
            </TR>
            <TR>
                <TD width="84">cmbValeurs</TD>
                <TD><%=cmbValeurs%></TD>
            </TR>
            <TR>
                <TD width="84">lstSimple</TD>
                <TD><%=lstSimple%></TD>
            </TR>
            <TR>
                <TD width="84">lstMultiple</TD>
                <TD><%=lstMultiple%></TD>
            </TR>
            <TR>
                <TD width="84">secret</TD>
                <TD><%=secret%></TD>
            </TR>
        </TABLE>
    </body>
</HTML>

Dynamiczne fragmenty dokumentu <%=zmienna%> są obliczane przez powiązany kontroler [validation.aspx.vb]:


Imports System.Text.RegularExpressions

Public Class validation
    Inherits System.Web.UI.Page

    Protected rdMarie As String
    Protected C1 As String
    Protected C2 As String
    Protected C3 As String
    Protected txtSaisie As String
    Protected txtMdp As String
    Protected areaSaisie As String
    Protected cmbValeurs As String
    Protected lstSimple As String
    Protected lstMultiple As String
    Protected secret As String
    Protected delimiteur As New Regex("\r\n")

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'pobieramy parametry przesłane metodą POST
        rdMarie = getValue("rdMarie")
        C1 = getValue("C1")
        C2 = getValue("C2")
        C3 = getValue("C3")
        txtSaisie = getValue("txtSaisie")
        txtMdp = getValue("txtMdp")
        areaSaisie = String.Join(",", delimiteur.Split(getValue("areaSaisie")))
        cmbValeurs = getValue("cmbValeurs")
        lstSimple = getValue("lstSimple")
        lstMultiple = getValue("lstMultiple")
        secret = getValue("secret")
    End Sub

    Private Function getValue(ByVal champ As String) As String
        ' pobiera wartość pola [champ] z przesłanego żądania
        ' coś tam?
        If Request.Form(champ) Is Nothing Then Return ""
        ' pobieramy wartość lub wartości pola
        Dim valeurs() As String = Request.Form.GetValues(champ)
        Dim valeur As String = ""
        Dim i As Integer
        For i = 0 To valeurs.Length - 1
            valeur += "[" + valeurs(i) + "]"
        Next
        Return valeur
    End Function

End Class

Obliczanie wartości do wyświetlenia odbywa się w procedurze [Form_Load]. Wartość „przesłanego” pola uzyskuje się za pomocą funkcji getValue(C), gdzie C to nazwa pola. Najważniejsze cechy tej funkcji są następujące:

  • jeśli C nie występuje w przekazanym ciągu parametrów, wówczas jako wartość C zwracany jest pusty ciąg
  • w przeciwnym razie pobiera się tablicę wartości pola C za pomocą funkcji [Request.Form.GetValues(C)]. Wartości te są łączone w ciąg znaków w postaci [val1][val2]...[valn], gdzie [vali] jest wartością nr i pola C

Pole [areaSaisie] jest przetwarzane w szczególny sposób. Jego wartość jest wysyłana przez przeglądarkę w postaci areaSaisie=wiersz1\r\nwiersz2\r\n... gdzie \r to znak o kodzie ASCII 13 (powrót karetki), a \n to znak o kodzie ASCII 10 (przejście do nowego wiersza). Funkcja getValue(areaSaisie) jest zatem ciągiem znaków „linia1\r\nlinia2\r\n...”. Ciąg ten jest dzielony na linie za pomocą metody [Regex.Split]. W ten sposób otrzymujemy tablicę ciągów znaków {linia1,linia2,...}. Tablica ta jest przekształcana w ciąg znaków „linia1,linia2,...” za pomocą metody [String.Join]. To właśnie ten ostatni ciąg znaków zostanie wyświetlony jako wartość pola [areaSaisie]. Celem tego przykładu było pokazanie, w jaki sposób można uzyskać poszczególne wiersze pola HTML typu [TextArea].

5.4.5. Testy

Umieszczamy wszystkie pliki (global.asax, global.asax.vb, formulaire.aspx, validation.aspx, validation.aspx.vb) w folderze <application-path>. Uruchamiamy serwer Cassini z parametrami (<application-path>,/mvcform1). W folderze <application-path> tworzymy pusty plik o nazwie [default.aspx], a następnie wywołujemy adres URL [http://localhost/mvcform1]. Ponieważ [/mvcform1] jest wirtualną ścieżką do folderu, a nie do dokumentu, serwer WWW wyświetli dokument [default.aspx], jeśli taki istnieje. Właśnie dlatego go utworzyliśmy. Przed wyświetleniem zostanie uruchomiony skrypt [global.asax], który ostatecznie spowoduje wyświetlenie strony [formulaire.aspx]. Dlatego plik [default.aspx] może być pusty.

Załóżmy, że zatwierdzony formularz wygląda następująco:

Image

Kliknięcie przycisku [Envoyer] powoduje wyświetlenie następującej strony:

Image

Zwróćmy najpierw uwagę na adres URL odpowiedzi: [http://localhost/mvcform1/?action=validation]. Jest to URL z atrybutu [action] w tagu <form> formularza [formulaire.aspx]:


        <form name="formulaire" method="post" action="?action=validation">

Przyjrzyjmy się po kolei wartościom uzyskanym dla poszczególnych pól formularza:

pole
wartość
HTML
uwagi
rdMarie
tak
<input type="radio" value="tak"
name="rdMarie">Tak
<input type="radio" checked
value="nie" name="rdMarie">Nie
uzyskaną wartością jest atrybut [value] przycisku zaznaczonego
C1
jeden
<input type="checkbox"
value="un" name="C1">1
to samo
C2
dwa
<input type="checkbox"
zaznaczone value="dwa" name="C2">2
to samo
C3
 
<input type="checkbox"
value="trzy" name="C3">3
ten przycisk nie został zaznaczony przez użytkownika. Jego wartość nie została zatem przesłana przez przeglądarkę. W kodzie warunek [Request.Form("C3") is Nothing] był zatem spełniony.
txtSaisie
Programowanie
asp.net
<input type="text"
... name="txtSaisie">
uzyskaną wartością jest tekst znajdujący się w polu wprowadzania danych w momencie zatwierdzenia
txtMdp
mdp
<input type="password"
...name="txtMdp">
to samo
areaSaisie
podstawy
programowania stron internetowych
<textarea name="areaSaisie">
...</textarea>
to samo
cmbValeurs
3
<select name="cmbValeurs">
...
<option value="3">opcja3</option>
</select>
uzyskaną wartością jest atrybut [value] wybranej opcji
lstSimple
3
<select size="3" name="lstSimple">
....
<option value="3">lista3</option>
...
</select>
to samo
lstMultiple
2 4
<select multiple size="3" name="lstMultiple">
...
<option value="2">multiple2
</option>
...
<option value="4">multiple4
</option>
...
</select>
uzyskane wartości odpowiadają atrybutom [value] wybranych opcji
secret
uneValeur
<input type="hidden"
name="secret" value="uneValeur">
uzyskana wartość to atrybut [value] pola ukrytego

Zajmijmy się teraz listami. Załóżmy, że w momencie walidacji stan formularza jest następujący:

Image

  • opcja [choix1] jest zaznaczona w comboBox
  • w pozostałych dwóch listach nie jest zaznaczona żadna opcja. Aby to osiągnąć, użyto przycisków [Raz].

Oto strona wyświetlona po zatwierdzeniu:

Image

Gdy w liście nie wybrano żadnej wartości, przeglądarka nie wysyła parametru dla tej listy. W kodzie [validation.aspx.vb] wyrażenia [Request.Form("lstSimple")] i [Request.Form("lstMultiple")] są zatem równe stałej [Nothing], stąd wynik wyświetlony powyżej.

5.5. Zachowanie stanu strony

5.5.1. Zachowanie stanu strony za pomocą sesji

Kopiujemy całą poprzednią aplikację do nowego folderu. Na stronie [validation.aspx] dodajemy link umożliwiający użytkownikowi powrót do formularza:

Image

Zmianą, jaką należy wprowadzić na stronie [validation.aspx], jest dodanie linku:


.....
            <TR>
                <TD width="84">secret</TD>
                <TD><%=secret%></TD>
            </TR>
        </TABLE>
        <P>
            <a href="?action=formulaire">Retour au formulaire</a>
        </P>
    </body>
</HTML>

Atrybut [href] linku ma wartość adresu URL z jednym parametrem: [action=formulaire], co pozwala serwerowi rozpoznać, że ma wyświetlić formularz w stanie, w jakim znajdował się w momencie zatwierdzenia. Istnieje zatem różnica w stosunku do akcji [init], która wyświetla formularz predefiniowany. Adres URL z parametrem [?action=formulaire] w rzeczywistości nie ma adresu URL. Będzie on zatem taki sam jak ten, który umożliwił wyświetlenie strony walidacji. Jeśli przypomnimy sobie poprzednią analizę, jest to adres URL katalogu aplikacji. Żądanie przejdzie zatem przez kontroler. Kontroler musi teraz przetworzyć akcję [formulaire]. Kod akcji [global.asax.vb] zostaje zmodyfikowany w następujący sposób:


    Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
        ' pobieramy czynność do wykonania
        Dim action As String
        If Request.QueryString("action") Is Nothing Then
            action = "init"
        Else
            action = Request.QueryString("action").ToString.ToLower
        End If
        ' wykonuje się działanie
        Select Case action
            Case "init"
                Server.Transfer("formulaire.aspx", False)
            Case "validation"
                Server.Transfer("validation.aspx", True)
            Case "formulaire"
                Server.Transfer("formulaire.aspx", True)
            Case Else
                Server.Transfer("formulaire.aspx", True)
        End Select
    End Sub

W przypadku, gdy akcją jest „formularz”, wystarczy przekazać żądanie do strony [formulaire.aspx]. Wiemy, że strona ta wyświetla predefiniowany formularz, w którym nie ma żadnych zmiennych elementów. Strona ta nie może zatem wyświetlić formularza z wartościami, jakie posiadał w momencie zatwierdzenia. Chcemy tutaj podkreślić tę kwestię. Jeśli wszystkie pliki aplikacji zostały umieszczone w <application-path>, uruchamiamy Cassini z parametrami (<application-path>,/mvcform2), a następnie wywołujemy adres URL [http://localhost/mvcform2]. Otrzymujemy następującą stronę (fragment):

Image

Wypełniamy formularz w następujący sposób, a następnie go zatwierdzamy:

Image

Otrzymujemy następującą stronę potwierdzenia:

Image

Korzystamy z linku [Retour au formulaire], który znajduje się (ale nie jest widoczny) na powyższej stronie. Otrzymujemy następującą odpowiedź z serwera:

Image

Stwierdzamy, że:

  • żądany adres URL zawiera parametr action=formularz, zgodnie z oczekiwaniami
  • wyświetlony formularz utracił wprowadzone wartości.

Wiemy, dlaczego nie odzyskujemy wprowadzonych wartości. Jeśli przyjrzymy się kodowi dokumentu [formulaire.aspx], zauważymy, że wszystko jest statyczne i w związku z tym za każdym razem wyświetlana jest ta sama strona. Wyraźnie widać, że musimy uczynić ten kod dynamicznym. Musi on wyświetlać wartości zatwierdzone przez użytkownika. Ale gdzie je zapisać?

Przypomnijmy żelazną zasadę protokołu bezstanowego HTTP:

  • adres URL [http://localhost/mvcform2] jest wywoływany – otrzymana zostaje odpowiedź. Połączenie TCP-IP zostało otwarte między klientem a serwerem na początku żądania i zamknięte po zakończeniu odpowiedzi.
  • Użytkownik wprowadza, a następnie zatwierdza dane. Wysyłane jest żądanie adresu URL [http://localhost/mvcform2/?action=validation] – otrzymana zostaje odpowiedź. Między obydwoma partnerami otwarto, a następnie zamknięto nowe połączenie o numerze TCP-IP.
  • Użytkownik korzysta z linku [Retour au formulaire]. Wysyłane jest żądanie do adresu URL [http://localhost/mvcform2/?action=formulaire] – otrzymana zostaje odpowiedź. Pomiędzy obydwoma partnerami ponownie otwarto, a następnie zamknięto nowe połączenie o numerze TCP-IP.

Cykle żądania-odpowiedzi są od siebie niezależne, ponieważ każdy z nich wykorzystuje nowe połączenie o numerze TCP-IP. Gdy aplikacja klient-serwer wykorzystuje jedno połączenie TCP-IP do serii wymian danych, serwer może zidentyfikować klienta na podstawie jego połączenia. Może zatem zapamiętać informacje, które powiąże z konkretnym połączeniem, i w ten sposób śledzić przebieg wymiany danych. Gdy wymiana danych odbywa się za pośrednictwem różnych połączeń, serwer nie jest w stanie zidentyfikować klienta na podstawie połączenia. Potrzebne jest inne rozwiązanie. Jedno z nich przedstawiliśmy w poprzednim rozdziale: mechanizm sesji. Pozwala on cyklom żądania-odpowiedzi na zapisywanie informacji w obiekcie [Session], dostępnym dla wszystkich kolejnych cykli.

Teraz, gdy mamy aplikację MVC z sesją, nie możemy już używać pliku [global.asax] jako kontrolera, tak jak pokazano w poprzednim rozdziale. Rolę kontrolera aplikacji musi pełnić specjalna strona przeznaczona do tego celu. W tym przypadku będzie to strona [main.aspx]. Postąpimy w następujący sposób:

  • gdy użytkownik zatwierdzi swoje dane (akcja=walidacja), kontroler [main.aspx.vb] zapisze je w bieżącej sesji, a następnie wyświetli stronę walidacji.
  • gdy konieczne będzie wyświetlenie formularza z wprowadzonymi wartościami (action=formularz), kontroler [main.aspx.vb] pobierze je z sesji i umieści w kontekście przed wyświetleniem formularza.

5.5.2. Nowy kontroler aplikacji

Kontroler aplikacji składa się z dwóch plików [main.aspx, main.aspx.vb]:

[main.aspx]

<%@ Page src="main.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="main" %>

[main.aspx.vb]


Imports System.Collections.Specialized
Imports Microsoft.VisualBasic

Public Class main
    Inherits System.Web.UI.Page

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' pobieramy czynność do wykonania
        Dim action As String
        If Request.QueryString("action") Is Nothing Then
            action = "init"
        Else
            action = Request.QueryString("action").ToString.ToLower
        End If
        ' wykonuje się działanie
        Select Case action
            Case "init"
                ' wyświetla się wstępnie wypełniony formularz
                Context.Items("formulaire") = initForm()
                Server.Transfer("formulaire.aspx", True)
            Case "validation"
                ' wyświetla stronę potwierdzenia po zapisaniu wartości przesłanych w sesji
                Session.Item("formulaire") = Request.Form
                Server.Transfer("validation.aspx", True)
            Case "formulaire"
                ' wyświetla się formularz z wartościami pobranymi z sesji
                Context.Items("formulaire") = Session.Item("formulaire")
                Server.Transfer("formulaire.aspx", True)
            Case Else
                ' wyświetla się wstępnie wypełniony formularz
                Context.Items("formulaire") = initForm()
                Server.Transfer("formulaire.aspx", True)
        End Select
    End Sub

    Private Function initForm() As NameValueCollection
        ' formularz jest inicjowany
        Dim form As New NameValueCollection
        form.Set("rdMarie", "non")
        form.Set("C2", "deux")
        form.Set("txtSaisie", "qqs mots")
        form.Set("txtMdp", "ceciestsecret")
        form.Set("areasaisie", "ligne1" + ControlChars.CrLf + "ligne2" + ControlChars.CrLf)
        form.Set("cmbValeurs", "2")
        form.Set("lstSimple", "1")
        form.Set("lstMultiple", "1")
        form.Add("lstMultiple", "3")
        Return form
    End Function
End Class

Znajdujemy tu istotę struktury kontrolera aplikacji omówionego wcześniej, z następującymi różnicami:

  • praca kontrolera odbywa się w procedurze [Form_Load]
  • w przypadku akcji [validation] wartości formularza obecne w [Request.Form] są zapisywane w sesji powiązanej z kluczem „formularz”. Następnie wykonanie jest przekazywane do strony [validation.aspx], która wyświetli te wartości.
  • W przypadku pozostałych akcji wykonanie jest zawsze przekazywane do strony [formulaire.aspx]. Strona ta oczekuje w swoim kontekście klucza „formularz”, który będzie powiązany z obiektem typu [Request.form], c.a.d lub typu [NameValueCollection]. Obiekt ten musi zawierać zbiór wartości pól formularza.
  • W przypadku, gdy akcją jest [init] lub akcja nierozpoznana, zbiór wartości jest tworzony arbitralnie przez funkcję [initForm].
  • W przypadku, gdy akcją jest [formulaire], zbiorem tym jest zbiór [Request.Form], który został umieszczony w sesji przez akcję [validation]

5.5.3. Nowy formularz

Ponieważ aplikacja nie wyświetla już tej samej treści w formularzu, musi on być generowany dynamicznie. Nowa strona [formulaire.aspx] wygląda następująco:


<%@ Page src="formulaire.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="formulaire" %>
<HTML>
    <HEAD>
        <title>Formulaire</title>
        <script language="javascript">
        function effacer(){
            alert("Vous avez cliqué sur le bouton [Effacer]");
        }
        function raz(liste){
            liste.selectedIndex=-1
        }
        </script>
    </HEAD>
    <body>
        <p>
            Gestion d'un formulaire
        </p>
        <hr>
        <form name="formulaire" method="post" action="main.aspx?action=validation">
            <table border="1">
                <tr>
                    <td>
                        Etes-vous marié(e)</td>
                    <td>
                        <p align="center">
                            <INPUT type="radio" value="oui" name="rdMarie" <%=rdouichecked%>>Oui
                         <INPUT type="radio" value="non" name="rdMarie" <%=rdnonchecked%>>Non
                        </p>
                    </td>
                </tr>
                <TR>
                    <TD>Cases à cocher
                    </TD>
                    <TD>
                        <P align="center">
                            <INPUT type="checkbox" value="un" name="C1" <%=c1checked%>>1
                             <INPUT type="checkbox" value="deux" name="C2" <%=c2checked%>>2
                            <INPUT type="checkbox" value="trois" name="C3" <%=c3checked%>>3
                        </P>
                    </TD>
                </TR>
                <TR>
                    <TD>Champ de saisie</TD>
                    <TD>
                        <P align="center">
                            <INPUT type="text" maxLength="30" value="<%=txtSaisie%>" name="txtSaisie">
                        </P>
                    </TD>
                </TR>
                <tr>
                    <td>
                        Mot de passe</td>
                    <td>
                        <p align="center">
                            <input type="password" maxlength="12" size="12" value="<%=txtMdp%>" name="txtMdp">
                        </p>
                    </td>
                </tr>
                <tr>
                    <td>
                        Boîte de saisie</td>
                    <td>
                        <textarea name="areaSaisie"><%=areaSaisie%></textarea>
                    </td>
                </tr>
                <tr>
                    <td>
                        ComboBox</td>
                    <td>
                        <select name="cmbValeurs">
                            <%=cmbValeursOptions%>
                        </select>
                    </td>
                </tr>
                <tr>
                    <td>
                        Liste à choix simple</td>
                    <td>
                        <select size="3" name="lstSimple">
                            <%=lstSimpleOptions%>
                        </select>
                        <INPUT type="button" value="Raz" name="btnRazSimple" onclick="raz(lstSimple)">
                    </td>
                </tr>
                <tr>
                    <td>
                        Liste à choix multiple</td>
                    <td>
                        <select multiple size="3" name="lstMultiple">
                            <%=lstMultipleOptions%>
                        </select>
                        <INPUT type="button" value="Raz" name="btnRazMultiple" onclick="raz(lstMultiple)">
                    </td>
                </tr>
                <tr>
                    <td>
                        Bouton simple</td>
                    <td>
                        <p align="center">
                            <input onclick="effacer()" type="button" value="Effacer" name="btnEffacer">
                        </p>
                    </td>
                </tr>
                <tr>
                    <td>
                        Bouton submit</td>
                    <td>
                        <p align="center">
                            <input type="submit" value="Envoyer" name="btnEnvoyer">
                        </p>
                    </td>
                </tr>
                <tr>
                    <td>
                        Bouton reset</td>
                    <td>
                        <p align="center">
                            <input type="reset" value="Rétablir" name="btnRetablir" runat="server">
                        </p>
                    </td>
                </tr>
            </table>
            <input type="hidden" name="secret" value="uneValeur">
        </form>
    </body>
</HTML>

Omówmy zmienne dynamiczne występujące w kodzie HTML:

zmienna
rola
rdouichecked
będzie miała wartość „checked”, jeśli przycisk opcji [oui] ma być zaznaczony, w przeciwnym razie wartość „”
rdnonchecked
to samo dotyczy przycisku opcji [non]
c1checked
to samo dotyczy pola wyboru [C1]
c2checked
to samo dotyczy pola wyboru [C2]
c3checked
to samo dotyczy pola wyboru [C3]
txtSaisie
tekst, który ma zostać umieszczony w polu [txtSaisie]
txtMdp
tekst, który ma zostać umieszczony w polu [txtMdp]
areaSaisie
tekst do umieszczenia w polu [areaSaisie]
cmbValeursOptions
tekst HTML z opcji listy rozwijanej [cmbValeurs]
lstSimpleOptions
tekst HTML z opcji listy rozwijanej [lstSimple]
lstMultipleOptions
tekst HTML z opcji listy rozwijanej [lstMultiple]
  

Wartości tych zmiennych są obliczane przez kontroler strony [formulaire.aspx.vb]:


Imports Microsoft.VisualBasic
Imports System.Collections.Specialized

Public Class formulaire
    Inherits System.Web.UI.Page

    ' stałe pola formularza
    Private libellésCmbValeurs() As String = {"choix1", "choix2", "choix3"}
    Private valeursCmbValeurs() As String = {"1", "2", "3"}
    Private libellésLstSimple() As String = {"liste1", "liste2", "liste3"}
    Private valeursLstSimple() As String = {"1", "2", "3"}
    Private libellésLstMultiple() As String = {"multiple1", "multiple2", "multiple3", "multiple4", "multiple5"}
    Private valeursLstMultiple() As String = {"1", "2", "3", "4", "5"}

    ' dynamiczne pola formularza
    Protected rdouichecked As String
    Protected rdnonchecked As String
    Protected c1checked As String
    Protected c2checked As String
    Protected c3checked As String
    Protected txtSaisie As String
    Protected txtMdp As String
    Protected areaSaisie As String
    Protected cmbValeursOptions As String
    Protected lstSimpleOptions As String
    Protected lstMultipleOptions As String

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' pobieramy poprzednie zapytanie z sesji
        Dim form As NameValueCollection
        If Not Context.Items("formulaire") Is Nothing Then
            form = Context.Items("formulaire")
        Else
            form = New NameValueCollection
        End If
        ' przygotowuje się stronę do wyświetlenia
        ' przyciski opcji
        rdouichecked = ""
        rdnonchecked = "checked"
        If isEqual(form("rdMarie"), "oui") Then
            rdouichecked = "checked"
            rdnonchecked = ""
        End If
        ' pola wyboru
        c1checked = ""
        If isEqual(form("C1"), "un") Then c1checked = "checked"
        c2checked = ""
        If isEqual(form("C2"), "deux") Then c2checked = "checked"
        c3checked = ""
        If isEqual(form("C3"), "trois") Then c3checked = "checked"
        ' pola wprowadzania danych
        txtSaisie = ""
        If Not form("txtSaisie") Is Nothing Then txtSaisie = form("txtSaisie").ToString
        txtMdp = ""
        If Not form("txtMdp") Is Nothing Then txtMdp = form("txtMdp").ToString
        areaSaisie = ""
        If Not form("areaSaisie") Is Nothing Then areaSaisie = form("areaSaisie").ToString
        ' listy
        Dim sélections() As String = {}
        If Not form("cmbValeurs") Is Nothing Then sélections = form.GetValues("cmbValeurs")
        cmbValeursOptions = getOptions(valeursCmbValeurs, libellésCmbValeurs, sélections)
        sélections = New String() {}
        If Not form("lstSimple") Is Nothing Then sélections = form.GetValues("lstSimple")
        lstSimpleOptions = getOptions(valeursLstSimple, libellésLstSimple, sélections)
        sélections = New String() {}
        If Not form("lstMultiple") Is Nothing Then sélections = form.GetValues("lstMultiple")
        lstMultipleOptions = getOptions(valeursLstMultiple, libellésLstMultiple, sélections)
    End Sub

    Private Function getOptions(ByRef valeurs() As String, ByRef libelles() As String, ByRef sélections() As String) As String
        ' zwraca kod HTML opcji tagu <select>
        ' wartości: tabela wartości opcji tagu
        ' nazwy: tabela nazw opcji tagu
        ' wybory: opcje do wyboru
        Dim iValeur As Integer
        Dim iSelection As Integer
        Dim selected As String
        Dim toString As String = ""
        ' przeglądamy listę wartości opcji
        For iValeur = 0 To valeurs.Length - 1
            ' sprawdza się, czy bieżąca wartość ma zostać zaznaczona
            selected = "" : iSelection = 0
            Do While iSelection < sélections.Length And selected = ""
                If valeurs(iValeur) = sélections(iSelection) Then selected = "selected"
                iSelection += 1
            Loop
            ' wstawia się kod HTML opcji
            toString += "<option " + selected + " value='" + valeurs(iValeur) + "'> " _
            + libelles(iValeur) + "</option>" + ControlChars.CrLf
        Next
        ' zwracamy wynik
        Return toString
    End Function

    Private Function isEqual(Byval champ As Object, ByVal valeur As String) As Boolean
        ' zwraca wartość „prawda”, jeśli pole jest równe wartości
        If champ Is Nothing OrElse champ.ToString <> valeur Then
            Return false
        Else
            Return true
        End If
    end function
End Class

Gdy strona [formulaire.aspx] rozpocznie działanie, znajdzie w swoim kontekście klucz „formularz” powiązany z zbiorem wartości pól, które ma wyświetlić.


         ' pobieramy poprzednie zapytanie z sesji
        Dim form As NameValueCollection
        If Not Context.Items("formulaire") Is Nothing Then
            form = Context.Items("formulaire")
        Else
            form = New NameValueCollection
        End If

Można się zastanawiać, dlaczego sprawdzane jest, czy obiekt [Context.Items("formulaire")] istnieje. W rzeczywistości kontroler przypisuje wartość do tego obiektu w każdym przypadku. Nic jednak nie stoi na przeszkodzie, aby klient zażądał bezpośrednio strony [formulaire.aspx], omijając kontroler. W takim przypadku powyższy kod będzie działał z pustą kolekcją wartości, ale nie dojdzie do „zawieszenia”.

Kod przegląda otrzymaną kolekcję wartości w celu obliczenia wszystkich zmiennych dynamicznych strony HTML, która jest z nią powiązana. Chociaż kod ten jest długi, nie jest szczególnie skomplikowany i pozostawiamy czytelnikowi możliwość samodzielnego zapoznania się z nim, aby nie przedłużać niniejszego wyjaśnienia. Skupimy się jednak na sposobie generowania kodu HTML z trzech list typu [select]. Kod ten jest generowany przez następującą funkcję:

    Private Function getOptions(ByRef valeurs() As String, ByRef libelles() As String, ByRef sélections() As String) As String
         ' zwraca kod HTML z opcji tagu <select>
         ' wartości: tablica wartości opcji tagu
         ' nazwy: tablica nazw opcji tagu
         ' wybory: opcje do wyboru
        Dim iValeur As Integer
        Dim iSelection As Integer
        Dim selected As String
        Dim toString As String = ""
         ' przeglądamy listę wartości opcji
        For iValeur = 0 To valeurs.Length - 1
             ' sprawdza się, czy bieżąca wartość ma zostać zaznaczona
            selected = "" : iSelection = 0
            Do While iSelection < sélections.Length And selected = ""
                If valeurs(iValeur) = sélections(iSelection) Then selected = "selected"
                iSelection += 1
            Loop
             ' wstawia się kod HTML opcji
            toString += "<option " + selected + " value='" + valeurs(iValeur) + "'> " _
            + libelles(iValeur) + "</option>" + ControlChars.CrLf
        Next
         ' zwracamy wynik
        Return toString
    End Function

Przypomnijmy, że opcje tagu <select> odpowiadają następującemu kodowi HTML:

<option [selected] value="...">texte</option>

Dla każdej opcji należy zatem wygenerować trzy informacje:

  • wartość opcji w atrybucie [value]
  • tekst opcji pomiędzy tagami <option> i </option>
  • słowo kluczowe [selected], jeśli opcja ma zostać zaznaczona na liście

Aby wygenerować te trzy informacje dla każdej z opcji, funkcja [getOptions] otrzymuje trzy wartości:

  1. tabela wartości opcji w [valeurs]
  2. tablicę tekstów opcji w [libelles]
  3. tabela wartości do wyboru w [sélections]

5.5.4. Strona zatwierdzania

Strona walidacji pozostaje bez zmian:

[validation.aspx]


<%@ Page src="validation.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="validation" %>
<HTML>
    <HEAD>
        <title>validation</title>
    </HEAD>
    <body>
        <P>Valeurs saisies</P>
        <HR width="100%" SIZE="1">
        <TABLE id="Table1" cellSpacing="1" cellPadding="1" width="300" border="1">
            <TR>
                <TD width="84">rdMarie</TD>
                <TD><% =rdMarie%></TD>
            </TR>
            <TR>
                <TD width="84">C1</TD>
                <TD><%=C1%></TD>
            </TR>
            <TR>
                <TD width="84">C2</TD>
                <TD><%=C2%></TD>
            </TR>
            <TR>
                <TD width="84">C3</TD>
                <TD><%=C3%></TD>
            </TR>
            <TR>
                <TD width="84">txtSaisie</TD>
                <TD><%=txtSaisie%></TD>
            </TR>
            <TR>
                <TD width="84">txtMdp</TD>
                <TD><%=txtMdp%></TD>
            </TR>
            <TR>
                <TD width="84">areaSaisie</TD>
                <TD><%=areaSaisie%></TD>
            </TR>
            <TR>
                <TD width="84">cmbValeurs</TD>
                <TD><%=cmbValeurs%></TD>
            </TR>
            <TR>
                <TD width="84">lstSimple</TD>
                <TD><%=lstSimple%></TD>
            </TR>
            <TR>
                <TD width="84">lstMultiple</TD>
                <TD><%=lstMultiple%></TD>
            </TR>
            <TR>
                <TD width="84">secret</TD>
                <TD><%=secret%></TD>
            </TR>
        </TABLE>
        <P>
            <a href="main.aspx?action=formulaire">Retour au formulaire</a>
        </P>
    </body>
</HTML>

[validation.aspx.vb]


Imports Microsoft.VisualBasic
Imports System.Text.RegularExpressions

Public Class validation
    Inherits System.Web.UI.Page

    Protected rdMarie As String
    Protected C1 As String
    Protected C2 As String
    Protected C3 As String
    Protected txtSaisie As String
    Protected txtMdp As String
    Protected areaSaisie As String
    Protected cmbValeurs As String
    Protected lstSimple As String
    Protected lstMultiple As String
    Protected secret As String
    Protected delimiteur As New Regex("\r\n")

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'pobieramy przesłane parametry
        rdMarie = getValue("rdMarie")
        C1 = getValue("C1")
        C2 = getValue("C2")
        C3 = getValue("C3")
        txtSaisie = getValue("txtSaisie")
        txtMdp = getValue("txtMdp")
        areaSaisie = String.Join(",", delimiteur.Split(getValue("areaSaisie")))
        cmbValeurs = getValue("cmbValeurs")
        lstSimple = getValue("lstSimple")
        lstMultiple = getValue("lstMultiple")
        secret = getValue("secret")
        ' zapisujemy je w sesji
        'Session("formularz") = Request.Form
    End Sub

    Private Function getValue(ByVal champ As String) As String
        ' pobieramy wartość pola [champ] z przesłanego żądania
        ' coś tam?
        If Request.Form(champ) Is Nothing Then Return ""
        ' pobiera wartość lub wartości z pola
        Dim valeurs() As String = Request.Form.GetValues(champ)
        Dim valeur As String = ""
        Dim i As Integer
        For i = 0 To valeurs.Length - 1
            valeur += "[" + valeurs(i) + "]"
        Next
        Return valeur
    End Function
End Class

5.5.5. Testy

Pliki [main.aspx, main.aspx.vb,formulaire.aspx,formulaire.aspx.vb, validation.aspx, validation.aspx.vb] umieszczamy w katalogu <application-path>, a Casini uruchamiamy z parametrami (<application-path>,/mvcform3). Następnie wywołujemy adres URL [http://localhost/mvcform3/main.aspx]. Otrzymujemy wstępnie zainicjowany formularz:

Image

Wypełniamy formularz w następujący sposób:

Image

Korzystamy z przycisku [Envoyer] znajdującego się powyżej. Otrzymujemy następującą odpowiedź z serwera:

Image

Korzystamy z powyższego linku [Retour au formulaire], aby powrócić do formularza. Otrzymujemy następującą nową odpowiedź:

Image

Formularz wyświetla się dokładnie tak, jak go zatwierdziliśmy.

5.5.6. Wniosek

Poprzedni przykład pokazał nam, że możliwe jest zachowanie stanu strony w trakcie cykli żądania-odpowiedzi między klientem a serwerem. Nie jest to jednak zadanie proste. W kolejnym rozdziale zobaczymy, że za pomocą ASP.NET można pozwolić serwerowi samodzielnie przywrócić stan strony.