Vytvořte si úhledný kontaktní formulář s podporou HTML5

V tomto tutoriálu se naučíme, jak vytvořit elegantní kontaktní formulář HTML5 AJAX. Formulář bude používat některé nové vstupní prvky a atributy HTML5 a bude ověřen pomocí vestavěného ověření formuláře v prohlížeči.

Použijeme jQuery a Modernizr, abychom pomohli se staršími prohlížeči, a PHP na straně serveru pro ověření vstupu.

Než se pustíte do tohoto výukového programu, podívejte se na naše šablony HTML5, protože kvalitní motiv může být dobrou volbou pro váš další projekt.

Krok 1:Začínáme

Pro začátek musíme nastavit náš adresář a soubory. Pro začátek velmi doporučuji standard HTML5. Toto je opravdu dobrý výchozí bod pro jakýkoli projekt HTML5 a ušetří vám spoustu času. Pro tento tutoriál jsem zvolil 'BOILERPLATE CUSTOM'.

Další informace o standardu HTML5 najdete v této příručce na Nettuts+.

Po stažení a rozbalení odstraňte vše kromě index.html a css a js složky. Také jsem přidal složku s názvem img a soubor PHP s názvem process.php . Použijeme img složka pro ukládání obrazových dat pro náš formulář a process.php pro zpracování veškeré logiky na straně serveru pro kontaktní formulář. Moje adresářová struktura nyní vypadá takto:

To je vše, co potřebujeme, abychom mohli začít! Standard HTML5 obsahuje úžasný reset CSS s rozumnými výchozími nastaveními a zahrnuje všechny knihovny JS (jQuery &Modernizr), které dnes budeme používat. Všechny naše soubory JS a CSS byly zapojeny do index soubor. Nyní je čas přejít k označení.

Krok 2:Formulář

Otevřete index.html a odstraňte vše v rámci #container živel. Náš kontaktní formulář vložíme do tohoto div :

<div id="contact-form" class="clearfix">
    <h1>Get In Touch!</h1>
    <h2>Fill out our super swanky HTML5 contact form below to get in touch with us! Please provide as much information as possible for us to help you with your enquiry :)</h2>
    <ul id="errors" class="">
        <li id="info">There were some problems with your form submission:</li>
    </ul>
    <p id="success">Thanks for your message! We will get back to you ASAP!</p>
    <form method="post" action="process.php">
        <label for="name">Name: <span class="required">*</span></label>
        <input type="text" id="name" name="name" value="" placeholder="John Doe" required="required" autofocus="autofocus" />
        
        <label for="email">Email Address: <span class="required">*</span></label>
        <input type="email" id="email" name="email" value="" placeholder="[email protected]" required="required" />
        
        <label for="telephone">Telephone: </label>
        <input type="tel" id="telephone" name="telephone" value="" />
        
        <label for="enquiry">Enquiry: </label>
        <select id="enquiry" name="enquiry">
            <option value="general">General</option>
            <option value="sales">Sales</option>
            <option value="support">Support</option>
        </select>
        
        <label for="message">Message: <span class="required">*</span></label>
        <textarea id="message" name="message" placeholder="Your message must be greater than 20 charcters" required="required" data-minlength="20"></textarea>
        
        <span id="loading"></span>
        <input type="submit" value="Holla!" id="submit-button" />
        <p id="req-field-desc"><span class="required">*</span> indicates a required field</p>
    </form>
</div>

Toto je vše HTML, co budeme pro náš formulář potřebovat. Podívejme se na každou jednotlivou sekci:

ul#errors and p#success budou držiteli našich chybových a úspěšných zpráv. Ve výchozím nastavení je skryjeme pomocí CSS a po odeslání formuláře je zobrazíme pomocí JavaScriptu nebo PHP. Pro zadání jména je naším jediným požadavkem, aby byl vyplněn.

V HTML5 to uděláme přidáním 'required' atribut. To donutí prohlížeč zkontrolovat, že toto pole má něco v sobě, než umožní odeslání formuláře. Pole e-mailu je podobné, ale kromě toho, že je povinné, chceme se skutečně ujistit, že se jedná o zadanou e-mailovou adresu. Za tímto účelem specifikujeme typ tohoto vstupu jako e-mail, což je v HTML5 nové. Přestože telefon není povinné pole, používáme k tomu vstupní typ tel HTML5.

Dotaz je standardní select a zpráva je typický textarea -- zde nic nového. Do textarea , nastavíme požadovaný atribut, abychom měli jistotu, že uživatel zadá nějaký text.

V HTML5 je nový atribut pro textové oblasti s názvem maxlength . Ano, uhodli jste, to nám umožňuje nastavit maximální počet znaků, které můžeme napsat do textové oblasti. Z nějakého hloupého důvodu si mocní, kteří vytvořili specifikaci HTML5, nemysleli, že bychom potřebovali atribut minlength (jako nyní) a žádný atribut pro to neexistuje. Takže jako provizorní atribut minlength použijeme další nový atribut HTML5 nazvaný atribut custom data. Toto je v podstatě jakýkoli název atributu s předponou 'data-'. V našem případě jsme vhodně zvolili data-minlength. To nám v podstatě umožňuje vytvářet vlastní atributy.

Další věc, která stojí za povšimnutí, je, že nastavujeme atribut s názvem placeholder na všech vstupních prvcích (kromě telefonu) a textové oblasti. Toto je nový vstupní atribut HTML5. Při prvním zobrazení formuláře se ve vstupu objeví zástupný text, obvykle v jiné barvě písma. Poté, když zaostříte na vstup, zástupný text zmizí. Pokud rozmažete bez vyplnění pole, zástupný text se vrátí zpět. To je docela skvělý efekt a může uživateli poskytnout trochu více informací o tom, co musí udělat. Dříve by to muselo být provedeno pomocí JavaScriptu.

Poslední věc, kterou je třeba si povšimnout, je, že vstup názvu má atribut HTML5, nazvaný autofocus . Při prvním načtení stránky se tento vstupní prvek okamžitě zaměří, aniž by uživatel musel cokoli dělat. To je také dobré pro vybídnutí uživatele, aby něco udělal.

To je vše HTML5, které začleníme do našeho značení. Pro podrobnější informace o těchto nových atributech a vstupech se podívejte na některé z těchto odkazů:

  • Povinný atribut
  • Atribut zástupného symbolu
  • Atribut automatického ostření
  • Typ vstupu e-mailu
  • Vlastní atribut dat
  • Typ telefonního vstupu
  • Prvek vstupu v HTML5

Krok 3:Úprava stylu formuláře

Tady je naše forma, která vypadá na nošení trochu hůř...

V tuto chvíli to nevypadá příliš dobře a naší zbrusu nové HTML5 dobrotě to moc nesvědčí, tak pojďme přidat nějaké CSS. Otevřete style.css soubor. Soubor již obsahuje některá resetování a výchozí nastavení, která nám pomohou zajistit kompatibilitu našeho formuláře x-browser. Přejděte dolů a vyhledejte komentář:

/*
    // ========================================== \\
   ||                                              ||
   ||               Your styles !                  ||
   ||                                              ||
    \\ ========================================== //
*/

Přímo za něj vložte následující CSS:

#contact-form {
    background-color:#F2F7F9;
    width:465px;
    padding:20px;
    margin: 50px auto;    
    border: 6px solid #8FB5C1;
    -moz-border-radius:15px;
    -webkit-border-radius:15px;
    border-radius:15px;
    position:relative;
}

#contact-form h1 {
    font-size:42px;
}

#contact-form h2 {
    margin-bottom:15px;
    font-style:italic;
    font-weight:normal;
}

#contact-form input, 
#contact-form select, 
#contact-form textarea, 
#contact-form label {
    font-size:15px;
    margin-bottom:2px;
}

#contact-form input, 
#contact-form select, 
#contact-form textarea {
    width:450px;
    border: 1px solid #CEE1E8;
    margin-bottom:20px;
    padding:4px;
}

#contact-form input:focus, 
#contact-form select:focus, 
#contact-form textarea:focus {
    border: 1px solid #AFCDD8;
    background-color: #EBF2F4;
}

#contact-form textarea {
    height:150px;
    resize: none;
}

#contact-form label {
    display:block;
}

#contact-form .required {
    font-weight:bold;
    color:#F00;    
}

#contact-form #submit-button {
    width: 100px;
    background-color:#333;
    color:#FFF;
    border:none;
    display:block;
    float:right;
    margin-bottom:0px;
    margin-right:6px;
    background-color:#8FB5C1;
    -moz-border-radius:8px;
}

#contact-form #submit-button:hover {
    background-color: #A6CFDD;
}

#contact-form #submit-button:active {
    position:relative;
    top:1px;
}

#contact-form #loading {
    width:32px;
    height:32px;
    background-image:url(../img/loading.gif);
    display:block;
    position:absolute;
    right:130px;
    bottom:16px;
    display:none;
}

#errors {
    border:solid 1px #E58E8E;
    padding:10px;
    margin:25px 0px;
    display:block;
    width:437px;
    -webkit-border-radius:8px;
    -moz-border-radius:8px;
    border-radius:8px;
    background:#FFE6E6 url(../img/cancel_48.png) no-repeat 405px center;
    display:none;
}

#errors li {
    padding:2px;
    list-style:none;    
}

#errors li:before {
    content: ' - ';    
}

#errors #info {
    font-weight:bold;
}

#errors #info:before {
    content: '';    
}

#success {
    border:solid 1px #83D186;
    padding:25px 10px;
    margin:25px 0px;
    display:block;
    width:437px;
    -webkit-border-radius:8px;
    -moz-border-radius:8px;
    border-radius:8px;
    background:#D3EDD3 url(../img/accepted_48.png) no-repeat 405px center;
    font-weight:bold;
    display:none;
}

#errors.visible, #success.visible {
    display:block;    
}

#req-field-desc {
    font-style:italic;
}

/* Remove box shadow firefox, chrome and opera put around required fields. It looks rubbish. */
input:required, textarea:required {
    -moz-box-shadow:none;
    -webkit-box-shadow:none;
    -o-box-shadow:none;
    box-shadow:none;
}

/* Normalize placeholder styles */

/* chrome, safari */
::-webkit-input-placeholder {
    color:#CCC;
    font-style:italic;
}

/* mozilla */
input:-moz-placeholder, textarea:-moz-placeholder {
    color:#CCC;
    font-style:italic;
}

/* ie (faux placeholder) */
input.placeholder-text, textarea.placeholder-text  { 
    color:#CCC;
    font-style:italic;
}

Pokud uložíte a znovu načtete, vaše stránka by nyní měla vypadat takto:

Teď to vypadá lépe! CSS je docela standardní, ale proberu několik věcí, které nejsou tak zřejmé:

#errors li:before {
    content: ' - ';    
}

Tím se vedle našich zpráv o ověření chyb vloží pomlčka. V podstatě nahrazuje odrážku v seznamu, jen si myslím, že to vypadá lépe.

#contact-form #submit-button:active {
    position:relative;
    top:1px;
}

To nám poskytne pěkný efekt „push-down“, když je aktivní tlačítko pro odeslání.

input:required, textarea:required {
    -moz-box-shadow:none;
    -webkit-box-shadow:none;
    -o-box-shadow:none;
    box-shadow:none;
}

Všechny prohlížeče (kromě IE) ve výchozím nastavení umisťují kolem požadovaných prvků stín červeného rámečku. Podle mého názoru to vypadá trochu přehnaně, takže to odstraním. Již jsem uvedl, že pole je povinné, tím, že do štítku vložím červenou hvězdičku.

/* chrome, safari */
::-webkit-input-placeholder {
    color:#CCC;
    font-style:italic;
}

/* mozilla */
input:-moz-placeholder, textarea:-moz-placeholder {
    color:#CCC;
    font-style:italic;
}

/* ie (faux placeholder) */
input.placeholder-text, textarea.placeholder-text  { 
    color:#CCC;
    font-style:italic;
}

Tím se normalizuje vzhled zástupného textu na vstupech a textových oblastech. Zde to uděláme světle šedou a kurzívou. To nám zajistí konzistenci napříč všemi prohlížeči kromě Opery, která nepodporuje styling zástupných symbolů. IE prostě nepodporuje zástupný atribut. Tečka. K polyfill budeme používat JavaScript. Více o stylování formulářů HTML5 pomocí CSS (2.1 + 3) si můžete přečíst zde.

V CSS si všimnete, že existuje několik odkazů na obrázky. Pokud je nemáte, jednoduše si stáhněte zdrojové soubory pro tento tutoriál a zkopírujte je.

Se značkami jsme skončili a vypadá to docela sladce. Vytvoříme záložní PHP pro případ, že prohlížeč uživatele nepodporuje nové vstupní atributy formuláře (IE) nebo pokud má uživatel vypnutý JavaScript. Později napíšeme nějaký JavaScript, abychom doplnili funkce, které prohlížeč postrádá. Ale v případě, že uživatel nemá pěkný nový prohlížeč nebo povolený JavaScript, musíme ještě potvrdit odeslání formuláře. Uděláme to na serveru pomocí PHP. Také jej použijeme k odeslání výsledků platného formuláře e-mailem.

Krok 4:Příprava na ověření na straně serveru

Pojďme se rovnou ponořit. Otevřete process.php a vložte následující:

<?php
if( isset($_POST) ){
    
    //form validation vars
    $formok = true;
    $errors = array();
    
    //sumbission data
    $ipaddress = $_SERVER['REMOTE_ADDR'];
    $date = date('d/m/Y');
    $time = date('H:i:s');
    
    //form data
    $name = $_POST['name'];    
    $email = $_POST['email'];
    $telephone = $_POST['telephone'];
    $enquiry = $_POST['enquiry'];
    $message = $_POST['message'];
    
    //form validation to go here....
    
}

Zde říkáme:spusťte tento následující kód pouze tehdy, když je metoda požadavku POST . Ve výchozím nastavení, pokud je formulář odeslán do skriptu PHP, jsou vstupní hodnoty formuláře uloženy v super globálním poli s názvem $_POST . Pokud není nic zveřejněno, $_POST nebude pole, příkaz if se bude rovnat false a náš kód nebude spuštěn.

Jakmile zjistíme, že se jedná o POST žádost, můžeme zahájit naši logiku zpracování formuláře. První věc, kterou musíme udělat, je nastavit dvě proměnné:

  • $formok: Booleovská hodnota, kterou můžeme na konci skriptu zkontrolovat, abychom zjistili, zda byl formulář platný nebo ne.
  • $errors: Pole, které použijeme k uložení všech problémů s formulářem, když jej ověřujeme.

Poté nastavíme některá obecná data pro odeslání formuláře:

  • $ipaddress: IP adresa uživatele, která může být užitečná pro zablokování spamu, křížové odkazy na analytická data atd.
  • $date: Datum odeslání formuláře. Používáme date funkce pro generování data ve formátu UK.
  • $time: Čas odeslání formuláře. Ke generování času používáme funkci data.

Pokud bychom chtěli, mohli bychom kombinovat datum a čas:

$datetime = date('d/m/Y H:i:s');

Rád je nechávám odděleně, abych je v případě potřeby mohl použít na jiné věci. Poslední sadou proměnných, kterou nastavujeme, jsou hodnoty odeslaných polí formuláře. Přistupujeme k $_POST pole předáním názvu pole formuláře jako klíče pro načtení dat pro každou proměnnou.

Krok 5:Ověření dat $_POST

Nyní zkontrolujeme každou proměnnou jednotlivě, abychom se ujistili, že jejich hodnota je platná. Pokud není, nastavíme $formok proměnná na false a uložte chybovou zprávu do $errors pole. Nejprve začneme polem se jménem.

//validate name is not empty
if(empty($name)){
    $formok = false;
    $errors[] = "You have not entered a name";
}

Zde se jen ujišťujeme, že $name ve skutečnosti má hodnotu. Pokud ne, znamená to, že uživatel nezadal jméno. Používáme empty() funkci pro kontrolu. [] po $errors je zkratka pro array_push (který se používá k přidání položky na konec pole). Dále ověříme e-mailovou adresu:

//validate email address is not empty
if(empty($email)){
    $formok = false;
    $errors[] = "You have not entered an email address";
//validate email address is valid
}elseif(!filter_var($email, FILTER_VALIDATE_EMAIL)){
    $formok = false;
    $errors[] = "You have not entered a valid email address";
}

Zkontrolujeme, zda byla skutečně zadána platná e-mailová adresa. Pro tento úkol použijeme filter_var() funkce. Nakonec budeme muset zprávu ověřit.

//validate message is not empty
if(empty($message)){
    $formok = false;
    $errors[] = "You have not entered a message";
}
//validate message is greater than 20 charcters
elseif(strlen($message) < 20){
    $formok = false;
    $errors[] = "Your message must be greater than 20 characters";
}

Ještě jednou zkontrolujeme, zda byla vložena zpráva. Pokud bylo něco zadáno, chceme se ujistit, že je delší než 20 znaků. K tomu použijeme strlen() funkce.

Pole telefonu a pole dotazu nejsou povinná pole, takže je není třeba ověřovat. Mohl bys, kdybys chtěl, ale pro účely tohoto tutoriálu nejsem.

Krok 6:Co dělat dále...

Jakmile ověříme výsledky formuláře, musíme se rozhodnout, zda uživateli poslat e-mail obsahující výsledky formuláře, nebo ne. Platnost formuláře jsme sledovali pomocí $formok variabilní. Pokud se stále rovná true , chceme odeslat výsledky formuláře, jinak ne.

Toto je logika, kterou použijeme k odeslání zprávy (vložte ji, až dokončíme ověření):

//send email if all is ok
if($formok){
    $headers = "From: [email protected]" . "\r\n";
    $headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
    
    $emailbody = "<p>You have recieved a new message from the enquiries form on your website.</p>
                  <p><strong>Name: </strong> {$name} </p>
                  <p><strong>Email Address: </strong> {$email} </p>
                  <p><strong>Telephone: </strong> {$telephone} </p>
                  <p><strong>Enquiry: </strong> {$enquiry} </p>
                  <p><strong>Message: </strong> {$message} </p>
                  <p>This message was sent from the IP Address: {$ipaddress} on {$date} at {$time}</p>";
    
    mail("[email protected]","New Enquiry",$emailbody,$headers);
    
}

K odeslání zprávy budeme používat mail() funkce. Této funkci budeme muset předat čtyři parametry:to, předmět, zprávu a hlavičky.

  • komu: Toto bude e-mailová adresa, na kterou chcete odeslat podrobnosti formuláře.
  • předmět: Toto bude předmět e-mailu.
  • zpráva: Toto bude obsah e-mailu. Toto ukládáme do proměnné $emailbody . Toto je HTML řetězec obsahující výsledky našeho formuláře. Tam, kde vidíte složené závorky s názvy našich proměnných, se tyto při spuštění tohoto skriptu změní na hodnotu proměnných. Tomu se říká variabilní substituce. Tento druh substituce funguje pouze v případě, že je řetězec zapouzdřen do DVOJITÝCH uvozovek, nikoli do SINGLE.
  • záhlaví: To se používá k předání dalších informací e-mailovému klientovi, aby věděl, jak e-mail interpretovat. Naše záhlaví ukládáme do $headers proměnnou a poskytuje dodatečné informace o tom, od koho e-mail pochází a jaký typ obsahu obsahuje.

Poznámka: Nezapomeňte změnit z e-mailovou adresu v záhlaví a komu e-mailovou adresu v mail funkce.

To by mělo vytvořit pěkný e-mail, jako je tento:

Pokud jste na serveru Windows, možná budete muset vložit tento řádek kódu (než deklarujete $headers proměnná), aby funkce pošty fungovala:

ini_set("sendmail_from","[email protected]");

Ať už bylo odeslání formuláře uživatelem platné nebo ne, chceme je vrátit zpět do formuláře. Pokud byl formulář platný a zpráva byla odeslána, musíme uživateli poskytnout zprávu o úspěchu. Pokud není platný, chceme zobrazit chybové zprávy uložené v $errors pole a také naplnit pole formuláře daty, která byla původně odeslána. Některé proměnné, které jsme v tomto skriptu používali, uložíme do pole a pošleme je spolu s přesměrováním zpět do formuláře.

//what we need to return back to our form
$returndata = array(
    'posted_form_data' => array(
        'name' => $name,
        'email' => $email,
        'telephone' => $telephone,
        'enquiry' => $enquiry,
        'message' => $message
    ),
    'form_ok' => $formok,
    'errors' => $errors
);

Naše data budeme ukládat v asociativním poli. Toto pole má tři členy:

  • posted_form_data: Toto bude pole obsahující data formuláře, která byla odeslána do skriptu.
  • form_ok: Uložíme $formok a tato proměnná bude zpětně zkontrolována na stránce formuláře, aby se uživateli aktualizovala odpovídající zpráva.
  • chyby: Uložíme $errors proměnná v tomto. Tato proměnná bude použita, pokud $formok proměnná se rovná false.

Poslední věcí, kterou musíme udělat, je přesměrovat uživatele zpět na stránku formuláře spolu s naším $returndata pole. Jakmile budeme přesměrováni zpět na stránku formuláře, ztratíme naše $returndata proměnná; tak, aby tato data trvala, dočasně je uložíme v relaci.

Další věc, kterou musíme mít na paměti, je, že pokud má prohlížeč uživatele povolen JavaScript, chceme formulář odeslat přes AJAX. To znamená, že budeme chtít, aby byl náš požadavek AJAX odeslán na stejné místo jako odeslání formuláře, když je JavaScript vypnutý. Protože formulář by již byl ověřen na straně klienta, projde všemi ověřeními na straně serveru a podrobnosti nám budou zaslány e-mailem. Pokud formulář není platný, nebude nikdy odeslán (protože tomu zabrání ověření prohlížeče / JavaScript). To znamená, že s požadavkem AJAX není důvod, abychom přesměrovali nebo nastavili jakékoli proměnné relace. V poslední části tohoto skriptu zkontrolujeme, zda aktuální požadavek na process.php byl požadavek AJAX nebo ne, a pokud byl, nastavte naše proměnné relace a přesměrování.

//if this is not an ajax request
if(empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) !== 'xmlhttprequest'){
    
    //set session variables
    session_start();
    $_SESSION['cf_returndata'] = $returndata;
    
    //redirect back to form
    header('location: ' . $_SERVER['HTTP_REFERER']);

}

Abychom zjistili, zda se jednalo o požadavek AJAX, hledáme proměnnou $_SERVER['HTTP_X_REQUESTED_WITH'] . Jako super globální $_POST existuje také pole s názvem $_SERVER . Toto pole obsahuje informace o serveru a spouštěcím prostředí. Podrobnější informace naleznete zde.

Potom zavoláme session_start() abyste nám poskytli přístup k relaci a nastavení proměnné $_SESSION['cf_returndata'] zrcadlit $returndata . Na stránce formuláře nyní budeme mít přístup k této proměnné.

Pro přesměrování zpět do formuláře používáme header() funkce. Říkáme mu, aby nás přesměroval na poslední stránku, ze které jsme přišli, pomocí proměnné:$_SERVER['HTTP_REFERER'] .

Celkem jste měli skončit s tímto:

<?php
if( isset($_POST) ){
    
    //form validation vars
    $formok = true;
    $errors = array();
    
    //submission data
    $ipaddress = $_SERVER['REMOTE_ADDR'];
    $date = date('d/m/Y');
    $time = date('H:i:s');
    
    //form data
    $name = $_POST['name'];    
    $email = $_POST['email'];
    $telephone = $_POST['telephone'];
    $enquiry = $_POST['enquiry'];
    $message = $_POST['message'];
    
    //validate form data
    
    //validate name is not empty
    if(empty($name)){
        $formok = false;
        $errors[] = "You have not entered a name";
    }
    
    //validate email address is not empty
    if(empty($email)){
        $formok = false;
        $errors[] = "You have not entered an email address";
    //validate email address is valid
    }elseif(!filter_var($email, FILTER_VALIDATE_EMAIL)){
        $formok = false;
        $errors[] = "You have not entered a valid email address";
    }
    
    //validate message is not empty
    if(empty($message)){
        $formok = false;
        $errors[] = "You have not entered a message";
    }
    //validate message is greater than 20 characters
    elseif(strlen($message) < 20){
        $formok = false;
        $errors[] = "Your message must be greater than 20 characters";
    }
    
    //send email if all is ok
    if($formok){
        $headers = "From: [email protected]" . "\r\n";
        $headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
        
        $emailbody = "<p>You have received a new message from the enquiries form on your website.</p>
                      <p><strong>Name: </strong> {$name} </p>
                      <p><strong>Email Address: </strong> {$email} </p>
                      <p><strong>Telephone: </strong> {$telephone} </p>
                      <p><strong>Enquiry: </strong> {$enquiry} </p>
                      <p><strong>Message: </strong> {$message} </p>
                      <p>This message was sent from the IP Address: {$ipaddress} on {$date} at {$time}</p>";
        
        mail("[email protected]","New Enquiry",$emailbody,$headers);
        
    }
    
    //what we need to return back to our form
    $returndata = array(
        'posted_form_data' => array(
            'name' => $name,
            'email' => $email,
            'telephone' => $telephone,
            'enquiry' => $enquiry,
            'message' => $message
        ),
        'form_ok' => $formok,
        'errors' => $errors
    );
        
    
    //if this is not an ajax request
    if(empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) !== 'xmlhttprequest'){
        //set session variables
        session_start();
        $_SESSION['cf_returndata'] = $returndata;
        
        //redirect back to form
        header('location: ' . $_SERVER['HTTP_REFERER']);
    }
}

To je vše pro zpracování našeho odeslání formuláře – hotovo a oprášeno pod 90 řádky PHP! Vše, co nyní musíme udělat, je aktualizovat uživatele a poskytnout buď zprávu o úspěchu, nebo chybovou zprávu. Můžete ušetřit process.php teď.

Krok 7:Aktualizujte uživatelské rozhraní

Nyní, když jsme zpracovali data formuláře a vrátili jsme se na stránku, musíme uživatele informovat o tom, co se stalo. To znamená přístup k proměnné session, kterou jsme nastavili na process.php a vymyslet, jakou odpověď dát. Protože tato stránka nyní potřebuje používat PHP, budeme muset změnit příponu souboru index.html na .php (index.html =index.php). Nebojte se, toto by nemělo narušit nic, co jsme již udělali.

První věc, kterou musíme udělat, je dostat naše proměnné z relace. K tomu potřebujeme přístup k relaci. Přímo v horní části stránky před jakýmkoli označením (nad doctype) vložte následující kód:

<?php session_start() ?>

Spuštění relace před odesláním jakéhokoli obsahu do prohlížeče by mělo zabránit chybám typu „nelze odeslat cookie relace – záhlaví již odeslal...“, které můžete obdržet. Pod H2 formuláře přidat do tohoto fragmentu PHP:

<?php
//init variables
$cf = array();
$sr = false;

if(isset($_SESSION['cf_returndata'])){
    $cf = $_SESSION['cf_returndata'];
    $sr = true;
}
?>

Dvě proměnné nastavujeme na výchozí hodnoty. Více o nich později... Pak zkontrolujeme, zda $_SESSION['cf_returndata'] je nastaven. Poté nastavíme $cf (zkratka pro kontaktní formulář), aby se rovnala naší proměnné relace. To jen proto, abychom nemuseli psát $_SESSION ... pokaždé, když chceme k těmto údajům přistupovat. Poslední proměnná $sr (krátká odezva serveru), je nastavena na true . Toto je proměnná, kterou budeme kontrolovat, abychom zjistili, zda jsme již dříve odeslali náš formulář. Další věc, kterou chceme udělat, je zobrazit chybovou zprávu nebo úspěch v horní části formuláře. Nahraďte toto:

<ul id="errors" class="">
    <li id="info">There were some problems with your form submission:</li>
</ul>
<p id="success">Thanks for your message! We will get back to you ASAP!</p>

S tímto:

<ul id="errors" class="<?php echo ($sr && !$cf['form_ok']) ? 'visible' : ''; ?>">
    <li id="info">There were some problems with your form submission:</li>
    <?php 
    if(isset($cf['errors']) && count($cf['errors']) > 0) :
        foreach($cf['errors'] as $error) :
    ?>
    <li><?php echo $error ?></li>
    <?php
        endforeach;
    endif;
    ?>
</ul>
<p id="success" class="<?php echo ($sr && $cf['form_ok']) ? 'visible' : ''; ?>">Thanks for your message! We will get back to you ASAP!</p>

Ve výchozím nastavení se zprávy vůbec nezobrazují, protože v CSS jsme nastavili 'display:none '. Uvnitř atributu class zpráv používáme PHP k přidání 'visible' třídy jim, pokud mají být ukázány. Tato třída nastavuje 'display' na 'block' .

<?php echo ($sr && !$cf['form_ok']) ? 'visible' : ''; ?>

Zde používáme ternární operátor, abychom ověřili, že...

  • a) odpověď serveru je rovna hodnotě true a
  • b) že formulář nebyl v pořádku
  • .

V podstatě, pokud jsme odeslali formulář, $sr se bude rovnat true a pokud byl formulář neplatný $cf['form_ok'] se bude rovnat false . Viditelná třída se tedy zobrazí, ale zobrazí se PHP a zpráva a naopak zpráva o úspěchu. Uvnitř závorky kontrolujeme hodnoty dvou proměnných. Ověřujeme, že $sr se rovná true a (&&) $cf['fomr_ok'] se rovná false . Ke kontrole těchto hodnot používáme zkratku. Můžete to také napsat takto, pokud chcete:

<?php echo ($sr === true && $cf['form_ok'] === false) ? 'visible' : ''; ?>

Jakmile jsme se rozhodli, kterou zprávu zobrazit, musíme kontejner naplnit relevantními daty. Zpráva o úspěchu se nemění, takže ji můžeme nechat tak, jak je. Chybová zpráva bude muset vyplnit chyby ověření. Abychom je zapsali, jednoduše procházíme naše pole chyb uložené v relaci a vyplňujeme li prvek uvnitř ul :

<ul id="errors" class="<?php echo ($sr && !$cf['form_ok']) ? 'visible' : ''; ?>">
    <li id="info">There were some problems with your form submission:</li>
    <?php 
    if(isset($cf['errors']) && count($cf['errors']) > 0) :
        foreach($cf['errors'] as $error) :
    ?>
    <li><?php echo $error ?></li>
    <?php
        endforeach;
    endif;
    ?>
</ul>

Nejprve zkontrolujeme, zda máme pole chyb v $cf a že obsahuje alespoň jednu chybu. if a foreach může vypadat trochu jinak, než jak jste je viděli dříve. Toto se nazývá alternativní syntaxe. Použili jsme zde alternativní syntaxi jen proto, aby byla trochu čitelnější, protože je smíchána s HTML. Pokud chcete, můžete použít normální syntaxi.

To je vše, co potřebujeme k tomu, abychom uživateli ukázali odpověď na odeslání formuláře. Chcete-li to vyzkoušet, vypněte JavaScript a odešlete formulář. Nezapomeňte, že prohlížeč ověří formulář, protože používáme nové prvky HTML5. Abych si byl jistý, že moje PHP funguje, testuji v IE8. Ano, je to tak, IE se občas hodí...

Pokud odešlete neplatný formulář, měli byste obdržet toto:

A pokud formulář vyplníte správně, měli byste dostat:

Také byste měli obdržet e-mail z kódu, který jsme napsali dříve (pokud jste formulář vyplnili správně). Nyní, když formulář funguje, poslední věc, kterou musíme udělat, je znovu vyplnit pole formuláře daty uživatele, pokud bylo odeslání neplatné. Zaměňte HTML uvnitř značek formuláře za toto:

<label for="name">Name: <span class="required">*</span></label>
<input type="text" id="name" name="name" value="<?php echo ($sr && !$cf['form_ok']) ? $cf['posted_form_data']['name'] : '' ?>" placeholder="John Doe" required="required" autofocus="autofocus" />

<label for="email">Email Address: <span class="required">*</span></label>
<input type="email" id="email" name="email" value="<?php echo ($sr && !$cf['form_ok']) ? $cf['posted_form_data']['email'] : '' ?>" placeholder="[email protected]" required="required" />

<label for="telephone">Telephone: </label>
<input type="tel" id="telephone" name="telephone" value="<?php echo ($sr && !$cf['form_ok']) ? $cf['posted_form_data']['telephone'] : '' ?>" />

<label for="enquiry">Enquiry: </label>
<select id="enquiry" name="enquiry">
    <option value="General" <?php echo ($sr && !$cf['form_ok'] && $cf['posted_form_data']['enquiry'] == 'General') ? "selected='selected'" : '' ?>>General</option>
    <option value="Sales" <?php echo ($sr && !$cf['form_ok'] && $cf['posted_form_data']['enquiry'] == 'Sales') ? "selected='selected'" : '' ?>>Sales</option>
    <option value="Support" <?php echo ($sr && !$cf['form_ok'] && $cf['posted_form_data']['enquiry'] == 'Support') ? "selected='selected'" : '' ?>>Support</option>
</select>

<label for="message">Message: <span class="required">*</span></label>
<textarea id="message" name="message" placeholder="Your message must be greater than 20 charcters" required="required" data-minlength="20"><?php echo ($sr && !$cf['form_ok']) ? $cf['posted_form_data']['message'] : '' ?></textarea>

<span id="loading"></span>
<input type="submit" value="Holla!" id="submit-button" />
<p id="req-field-desc"><span class="required">*</span> indicates a required field</p>

Jediný rozdíl je v tom, že k naplnění atributu value vstupů používáme PHP.

<?php echo ($sr && !$cf['form_ok']) ? $cf['posted_form_data']['name'] : '' ?>

Stejně jako u zpráv o úspěchu a chybových zprávách kontrolujeme, zda $sr se rovná true a cf['form_ok'] $ se rovná false a pokud jsou, vypíšeme uloženou hodnotu v relaci pro toto pole formuláře. To se provádí pomocí ternárního operátoru.

Na selectu děláme totéž, až na to, že místo zápisu uložené hodnoty musíme zkontrolovat každou hodnotu možnosti, abychom zjistili, zda odpovídá té uložené v relaci. Pokud se shoduje, vypíšeme vybraný atribut pro tuto možnost.

Konečně poslední věc, kterou uděláme, je unset tuto proměnnou relace poté, co z ní získáme data. Nemusíte to však dělat; záleží na preferenci. Pokud jej nyní zrušíte, když se stránka obnoví pomocí tlačítka pro obnovení (nikoli příspěvku formuláře), nebude se zobrazovat zpráva o chybě / úspěchu. Pokud jste jej nezrušili, uživatel může vyplnit kontaktní formulář, procházet se po internetu, vrátit se do formuláře a chybová / úspěšná zpráva se bude stále zobrazovat. Nelíbí se mi to, takže tomu zabráním tím, že za závěrečné značky formuláře vložím tento řádek PHP:

<?php unset($_SESSION['cf_returndata']); ?>

Pokud odešlete neplatný formulář, měli byste si nyní všimnout, že vstupní hodnoty formuláře jsou zachovány, a pokud na stránku odkazujete, zpráva a data by měla být vymazána. To je vše pro PHP stránku věci! Měli jste skončit s tím, že váš formulář bude vypadat takto:

<div id="contact-form" class="clearfix">
    <h1>Get In Touch!</h1>
    <h2>Fill out our super swanky HTML5 contact form below to get in touch with us! Please provide as much information as possible for us to help you with your enquiry :)</h2>
    <?php
    //init variables
    $cf = array();
    $sr = false;
    
    if(isset($_SESSION['cf_returndata'])){
        $cf = $_SESSION['cf_returndata'];
        $sr = true;
    }
    <ul id="errors" class="<?php echo ($sr && !$cf['form_ok']) ? 'visible' : ''; ?>">
        <li id="info">There were some problems with your form submission:</li>
        <?php 
        if(isset($cf['errors']) && count($cf['errors']) > 0) :
            foreach($cf['errors'] as $error) :
        ?>
        <li><?php echo $error ?></li>
        <?php
            endforeach;
        endif;
        ?>
    </ul>
    <form method="post" action="process.php">
        <label for="name">Name: <span class="required">*</span></label>
        <input type="text" id="name" name="name" value="<?php echo ($sr && !$cf['form_ok']) ? $cf['posted_form_data']['name'] : '' ?>" placeholder="John Doe" required autofocus />
        
        <label for="email">Email Address: <span class="required">*</span></label>
        <input type="email" id="email" name="email" value="<?php echo ($sr && !$cf['form_ok']) ? $cf['posted_form_data']['email'] : '' ?>" placeholder="[email protected]" required />
        
        <label for="telephone">Telephone: </label>
        <input type="tel" id="telephone" name="telephone" value="<?php echo ($sr && !$cf['form_ok']) ? $cf['posted_form_data']['telephone'] : '' ?>" />
        
        <label for="enquiry">Enquiry: </label>
        <select id="enquiry" name="enquiry">
            <option value="General" <?php echo ($sr && !$cf['form_ok'] && $cf['posted_form_data']['enquiry'] == 'General') ? "selected='selected'" : '' ?>>General</option>
            <option value="Sales" <?php echo ($sr && !$cf['form_ok'] && $cf['posted_form_data']['enquiry'] == 'Sales') ? "selected='selected'" : '' ?>>Sales</option>
            <option value="Support" <?php echo ($sr && !$cf['form_ok'] && $cf['posted_form_data']['enquiry'] == 'Support') ? "selected='selected'" : '' ?>>Support</option>
        </select>
        
        <label for="message">Message: <span class="required">*</span></label>
        <textarea id="message" name="message" placeholder="Your message must be greater than 20 charcters" required data-minlength="20"><?php echo ($sr && !$cf['form_ok']) ? $cf['posted_form_data']['message'] : '' ?></textarea>
        
        <span id="loading"></span>
        <input type="submit" value="Holla!" id="submit-button" />
        <p id="req-field-desc"><span class="required">*</span> indicates a required field</p>
    </form>
    <?php unset($_SESSION['cf_returndata']); ?>
</div>

Nezapomeňte na session_start() přímo v horní části stránky! Nyní máme plně funkční kontaktní formulář.

Data jsou ověřena, a pokud budou úspěšní, zašleme nám e-mailem výsledky formuláře. Dále aktualizujeme uživatelské rozhraní s výsledky pro každý příspěvek. Novější prohlížeče dokonce ověří formulář před jeho odesláním pomocí nových typů vstupu HTML5 a atributů, které jsme použili.

To je všechno v pořádku, ale můžeme věci posunout ještě o krok dále. Můžeme použít JavaScript k polyfill funkcí, které prohlížeč nemá (zabudovaná validace, podpora HTML5 atributů atd.). Můžeme dokonce použít JavaScript k zobrazení našich chybových / úspěšných zpráv a odeslání formuláře pomocí AJAX.

Ale proč to dělat, když formulář již funguje? No, je to jednoduché. Chceme poskytnout co největší konzistenci ve všech prohlížečích, i když je to opravdu naff prohlížeč. Pokud také přimějeme prohlížeč klienta, aby zvládl veškerou validační práci, šetří to zdroje našeho serveru, protože na něj neposíláme, když formulář není platný. Tyto věci jsou super hnědé body a opravdu to není tak těžké.

Krok 8:Co je to Polyfill?

"Polyfill nebo polyfiller je část kódu, která poskytuje technologii, kterou jako vývojář očekáváte, že prohlížeč bude poskytovat nativně."

V našem případě očekáváme, že prohlížeč bude podporovat nové typy vstupu HTML5 a atributy, které jsme použili. Firefox, Chrome, Opera a Safari pro ně mají docela dobrou nativní podporu. IE6 - 9 pro ně nemá žádnou podporu. Typický. Abych byl upřímný, je to docela šokující IE9 nemá podporu pro tyto věci, byl teprve vydán začátkem tohoto roku. Každopádně, pomineme-li mlácení IE (mohl bych pokračovat donekonečna), první dvě věci, které se chystáme polyfill, jsou autofocus a placeholder atribut.

S naším JavaScriptem nám pomůže jQuery. Použijeme jej především ke zpracování našich požadavků AJAX, animací a procházení a manipulace DOM. Mohli byste se dostat pryč s tím, že ji nebudete používat, ale museli byste napsat značné množství kódu. Jeho půdorys není příliš velký, takže mohu žít s velikostí souboru. Asi jako vy bych raději psal méně kódu.

Budeme také používat knihovnu JavaScript s názvem Modernizr, která nám pomůže s detekcí funkcí. Toto je již zahrnuto jako součást našeho standardu HTML5, takže zde nemusíme nic dělat, abychom Modernizr uvedli do provozu!

Přejděte na js adresář a otevřete script.js . Nemusíme si dělat starosti s připojením tohoto souboru, jQuery nebo Modernizr, na index.php protože nám to již poskytl standard HTML5, který jsme použili. Smažte vše v tomto souboru a vložte následující:

$(function(){

    //set global variables and cache DOM elements for reuse later
    var form = $('#contact-form').find('form'),
        formElements = form.find('input[type!="submit"],textarea'),
        formSubmitButton = form.find('[type="submit"]'),
        errorNotice = $('#errors'),
        successNotice = $('#success'),
        loading = $('#loading'),
        errorMessages = {
            required: ' is a required field',
            email: 'You have not entered a valid email address for the field: ',
            minlength: ' must be greater than '
        }

    //feature detection + polyfills
    formElements.each(function(){
    
        //do feature detection + polyfills here
        
    });
});

Veškerý náš kód bude žít uvnitř $(function(){ }) blok. To znamená, že náš kód bude spuštěn, jakmile se stránka načte. Také žádné proměnné nebo funkce, které deklarujeme uvnitř tohoto bloku, nebudou kolidovat s žádným jiným kódem vně. Poté ukládáme do mezipaměti některé prvky DOM, protože k nim budeme přistupovat poměrně dost. Je efektivnější je uložit do mezipaměti tímto způsobem, než je vyžadovat pokaždé, když je chcete použít. Zde je rozpis toho, co jsou jednotlivé proměnné:

  • formulář: Prvek kontaktního formuláře.
  • formElements: Všechny vstupní prvky a textové oblasti ve formuláři kromě tlačítka Odeslat. Toto bude pouze pole prvků.
  • formSubmitButton: Tlačítko pro odeslání formuláře.
  • chybové upozornění: Chybové oznámení -- prvek neuspořádaného seznamu.
  • Upozornění na úspěch: Zpráva o úspěchu -- prvek odstavce.
  • načítání: Prvek rozpětí zatížení. Po odeslání formuláře po ověření se zobrazí načítající se gif.
  • errorMessages: Toto je objekt obsahující nějaký text pro naše chybové zprávy. Ty se používají více než jednou, takže je zde vytváříme. Všimnete si, že některé zprávy se nečtou správně. Později je dynamicky přidáme, až přejdeme k ověření formuláře.

Poté používáme funkci jQuery nazvanou each() iterovat přes formElements pole. Zatímco procházíme prvky formuláře, chceme provést detekci funkcí pro zástupný atribut, a pokud prvek tento atribut má, ale prohlížeč jej nepodporuje, použijte naši polyfill. Zde je polyfill pro zástupný atribut:

//if HTML5 input placeholder attribute is not supported
if(!Modernizr.input.placeholder){
    var placeholderText = this.getAttribute('placeholder');
    if(placeholderText){
        $(this)
            .addClass('placeholder-text')
            .val(placeholderText)
            .bind('focus',function(){
                if(this.value == placeholderText){
                    $(this)
                        .val('')
                        .removeClass('placeholder-text');
                }
            })
            .bind('blur',function(){
                if(this.value == ''){
                    $(this)
                        .val(placeholderText)
                        .addClass('placeholder-text');
                }
            });
    }
}

Zde používáme Modernizr k určení, zda máme podporu pro zástupný atribut na vstupu. Modernizátor je objekt, input je vlastnost tohoto objektu a zástupný symbol je vlastnost input (proto všechny tečky). Tato hodnota bude buď true nebo false . Zjišťujeme, zda je false (prohlížeč nepodporuje zástupný atribut); pokud ano, implementujeme náš polyfill. První věc, kterou uděláme, je deklarovat proměnnou, která bude obsahovat zástupný text přiřazený k prvku. I když prohlížeč nepodporuje zástupný atribut, stále máme k tomuto atributu přístup. Používáme funkci nazvanou getAttribute() pro tohle. Klíčové slovo 'this' odkazuje na aktuální prvek DOM, přes který iterujeme ve smyčce.

Jakmile máme zástupný text, můžeme provést kontrolu, abychom se ujistili, že není prázdný. Je to proto, že naši polyfill aplikujeme pouze na vstupy, které mají zástupný atribut. Poté zřetězujeme některé opravdu užitečné funkce jQuery, abychom vytvořili náš polyfill. Zde je rozpis toho, co děláme:

  1. Klíčové slovo „toto“ zabalujeme do funkce jQuery ( $() ) takže máme přístup k některým praktickým funkcím DOM jQuery
  2. Přidáváme třídu 'placeholder-text k prvku. To způsobí, že zástupný text prvků, který se chystáme polyfill, bude vypadat jako ve zbytku prohlížečů. Nastavili jsme pro to pravidlo již v CSS.
  3. Výchozí hodnotu vstupu nastavujeme na hodnotu zástupného atributu. Po načtení stránky se ve vstupním poli zobrazí zástupný text.
  4. Svazujeme událost fokus, která zkontroluje, zda je text zástupného symbolu stejný jako hodnota inputs. Pokud ano, pak je hodnota vstupu nastavena na nic, čímž se vstup vymaže a odstraníme 'placeholder-text ', aby byl text výchozím vstupním stylem textu.
  5. Připojujeme událost rozmazání, která zkontroluje, zda se hodnota vstupu nerovná ničemu. Pokud ano, vyplníme vstup zástupným textem a znovu použijeme 'placeholder-text '

To způsobí, že každý prohlížeč, který nepodporuje zástupný atribut, se bude chovat přesvědčivě. Viz obrázek níže z IE8:

Dále vyplníme autofocus atribut. Tohle je smrtelně jednoduché:

//if HTML5 input autofocus attribute is not supported
if(!Modernizr.input.autofocus){
    if(this.getAttribute('autofocus')) this.focus();
}

K určení, zda je podporován atribut autofocus, používáme Modernizer. Pokud ne, pak zkontrolujeme, zda má tento prvek nastaven atribut autofocus, a pokud ano, zaostříme jej. Jednoduchý. V každém prohlížeči, který tento atribut nepodporuje, to poskytne opravu.

Jediné další věci, které potřebujeme k polyfill, jsou požadovaný atribut, typ vstupu e-mailu a vestavěné ověření formuláře. Chceme také přidat ověření délky zprávy a zobrazit chybovou zprávu s podrobnostmi o problémech s formulářem.

Krok 9:Ověření formuláře, styl polyfill

//to ensure compatibility with HTML5 forms, we have to validate the form on submit button click event rather than form submit event. 
//An invalid html5 form element will not trigger a form submit.
formSubmitButton.bind('click',function(){
    var formok = true,
        errors = [];
        
    formElements.each(function(){
           
        //validate form elements here
           
    });
    
    //if form is not valid
    if(!formok){
        
        //show error message here
        
    }
    //if form is valid
    else {
        
        //ajax request + show success message here
        
    }
    
    return false; //this stops submission off the form and also stops browsers showing default error message
});

Událost kliknutí vážeme na tlačítko odeslání formuláře (uložené v formSubmitButton proměnná). Když se tato událost spustí, ověříme formulář. Normálně bychom to v JavaScriptu skutečně provedli při události odeslání formuláře, ale protože novější prohlížeče používají vlastní vestavěné ověření, událost odeslání formuláře se nikdy nespustí. The browser will display its own error messages, but this is highly inconsistent accross all of the browsers, and there is currently no way of styling these. Displaying our own error message will provide consistency, and also show for browsers that do not support the new validation methods. To stop the browsers showing their default error messages we return false at the end of this function. Here is a breakdown of what the variables set at the top are for:

  • formok: This will keep track of the validity of the form.
  • errors: This is an array and will hold the error messages.

It's similar to the PHP validation we wrote earlier!

We will start inside the loop where we are going to be validating the form elements. Inside this loop, we want to start by declaring some useful variables that we will use in our validation.

var name = this.name,
    nameUC = name.ucfirst(),
    value = this.value,
    placeholderText = this.getAttribute('placeholder'),
    type = this.getAttribute('type'), //get type old school way
    isRequired = this.getAttribute('required'),
    minLength = this.getAttribute('data-minlength');
  • name: The name of the current element.
  • nameUC: The name of the current element with the first letter uppercased. ucfirst() is a custom method of the string object that we will be writing later.
  • value: The value of the current element.
  • placeholderText: The placeholder text of the current element.
  • type: The type of current element.
  • isRequired: Whether the current element has the required attribute set on it or not.
  • minLength: The data-minlength value of current element (if applicable).

Now that we have our variables set, we can start with our validation. For the elements that are using the HTML5 input types and attributes, we can use the new validation JavaScript API to check their validity.

In HTML5, form elements have a new property called validity . This is where all the validation data for this element is stored. In Firebug, this looks like so:

As you can see, there are numerous properties in this object which give us a bit more of a clue as to what the problem is. The values of the properties are either false or false . In this screenshot, I tried to submit the form with no name, and I logged the validity property for the name input in the console ( console.log(this.validity) ). This shows me that a value was missing (valueMissing = true ).

Our code for checking the HTML5 elements:

//if HTML5 formfields are supported            
if( (this.validity) && !this.validity.valid ){
    formok = false;
    
    //if there is a value missing
    if(this.validity.valueMissing){
        errors.push(nameUC + errorMessages.required);    
    }
    //if this is an email input and it is not valid
    else if(this.validity.typeMismatch && type == 'email'){
        errors.push(errorMessages.email + nameUC);
    }
    
    this.focus(); //safari does not focus element an invalid element
    return false;
}

We are checking whether this form element has the validity property, and if it does, we are then checking the valid property of the validity object to see if this field is ok. If it is not valid (I'm using the shorthand, !, to check for false ), we set formok to false , and perform some tests to see what the problem is.

If the value is missing (triggered by required fields), we add an error message to the errors array we set earlier. We use the push() method of the array object for this. The error message will consist of the element's name (first letter uppercased) concatenated with the required error message that we set earlier in our script.

If this form fields value is not missing, we then want to determine if the correct data was input. The only input in our form that needs validation is the email field. With this in mind, in the elseif part of our code, we are checking if the typeMismatch property of the validity object is equal to true and if this input's type is actually email. If so, we add the email error message to our errors array.

When the browser validates a field and is deemed invalid, it is automatically focused. Safari does not support this, so for the sake of consistency, we manually focus the input. We then return false at the end of our HTML5 input validation to break out of the loop, as we know that we have an invalid element (we don't need to waste our time validating the rest of the elements in the form).

This will cover our HTML5 inputs nicely, but we now need to cater to the browsers which do not support the JavaScript form validation API. If the JavaScript form validation API is not supported by the browser the above code will never be exectued and skipped.

The first thing we will check for is if the field was required. Our polyfill for this will look like:

//if this is a required element
if(isRequired){    
    //if HTML5 input required attribute is not supported
    if(!Modernizr.input.required){
        if(value == placeholderText){
            this.focus();
            formok = false;
            errors.push(nameUC + errorMessages.required);
            return false;
        }
    }
}

Firstly, we check if this field is a required field (dictated by the required attribute). We are then using Modernizr to check if the required attribute is supported by the browser. If not, we need to manually check the value of the element and compare it to the element's placeholder attribute. If they are the same, then obviously this form field has not been filled out so we do four things:

  1. We focus the input (as this what the browser does when using its native validation)
  2. We set the formok variable to false , as the form is invalid
  3. We add an error message to our errors array.
  4. We return false , which breaks out of the loop, and will go straight to the next bit of the code outside of the loop.

We are next going to check if this is an email input, and, if it is, whether a valid email has been entered.

//if HTML5 input email input is not supported
if(type == 'email'){     
    if(!Modernizr.inputtypes.email){ 
        var emailRegEx = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/; 
        if( !emailRegEx.test(value) ){    
            this.focus();
            formok = false;
            errors.push(errorMessages.email + nameUC);
            return false;
        }
    }
}

It's pretty much the same as before. We see if this is actually an email field, and then use Modernizr to check if the email input is supported. If it's not, we write our code that checks if it is valid or not. For this polyfill, we are using regular expressions to test if the email is valid or not. We create a regular expression in the variable emailRegEx , then use the test() method of the regular expression object to test if the value of the input is valid against the regular expression.

You can learn more on using JavaScript regular expressions here.

If the email address is not valid, we do the same four things we did on the required input check.

The last thing we need to validate in our form is the message length. The required validation has already been taken care of above, so all we need to do is check the message's length:

//check minimum lengths
if(minLength){
    if( value.length < parseInt(minLength) ){
        this.focus();
        formok = false;
        errors.push(nameUC + errorMessages.minlength + minLength + ' charcters');
        return false;
    }
}

We don't need to use Modernizr here. Instead, all we need to do is check that this element has a minimum length set, and if it does, make sure its length is greater than its set minimum length. Length is a property of all string objects in JavaScript and returns the number of characters in the string. We use parseInt() to convert minLength to an integer to compare it against value.length . minLength was retrieved from the data-minlength atribut. This is retrieved as a string, so to prevent any potential errors down the line (comparing strings to numbers etc.), we convert this to an integer.

Our polyfills and validation are now finished and sorted. You should have ended up with the following code:

//to ensure compatibility with HTML5 forms, we have to validate the form on submit button click event rather than form submit event. 
//An invalid html5 form element will not trigger a form submit.
formSubmitButton.bind('click',function(){
    var formok = true,
        errors = [];
        
    formElements.each(function(){
        var name = this.name,
            nameUC = name.ucfirst(),
            value = this.value,
            placeholderText = this.getAttribute('placeholder'),
            type = this.getAttribute('type'), //get type old school way
            isRequired = this.getAttribute('required'),
            minLength = this.getAttribute('data-minlength');
            
        //if HTML5 formfields are supported            
        if( (this.validity) && !this.validity.valid ){
            formok = false;
            
            //if there is a value missing
            if(this.validity.valueMissing){
                errors.push(nameUC + errorMessages.required);    
            }
            //if this is an email input and it is not valid
            else if(this.validity.typeMismatch && type == 'email'){
                errors.push(errorMessages.email + nameUC);
            }
            
            this.focus(); //safari does not focus element an invalid element
            return false;
        }
        
        //if this is a required element
        if(isRequired){    
            //if HTML5 input required attribute is not supported
            if(!Modernizr.input.required){
                if(value == placeholderText){
                    this.focus();
                    formok = false;
                    errors.push(nameUC + errorMessages.required);
                    return false;
                }
            }
        }

        //if HTML5 input email input is not supported
        if(type == 'email'){     
            if(!Modernizr.inputtypes.email){ 
                var emailRegEx = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/; 
                if( !emailRegEx.test(value) ){    
                    this.focus();
                    formok = false;
                    errors.push(errorMessages.email + nameUC);
                    return false;
                }
            }
        }
        
        //check minimum lengths
        if(minLength){
            if( value.length < parseInt(minLength) ){
                this.focus();
                formok = false;
                errors.push(nameUC + errorMessages.minlength + minLength + ' charcters');
                return false;
            }
        }
    });
    
    //if form is not valid
    if(!formok){
        
        //show error message here
        
    }
    //if form is valid
    else {
        
        //ajax request + show success message here
        
    }
    
    return false; //this stops submission off the form and also stops browsers showing default error message
});

Úžasný! We're nearly there now. At this point, all we need to do is write the code that handles the logic to check if the form is to be submitted or not. We will need to display our error messages that we have stored, and stop the form submitting if there is an error. If, on the other hand, there isn't an error, we submit the form via AJAX and reveal the success message. We also need to cover the ucfirst() function we have used to uppercase the first letter of each field name.

Step 11:Nearly There...

The first thing we are going to do is write a function for handling the messages, and also our ucfirst() funkce. Paste the following code outside the formSubmitButton.bind ... logic we have been writing.

//other misc functions
function showNotice(type,data)
{
    if(type == 'error'){
        successNotice.hide();
        errorNotice.find("li[id!='info']").remove();
        for(x in data){
            errorNotice.append('<li>'+data[x]+'</li>');    
        }
        errorNotice.show();
    }
    else {
        errorNotice.hide();
        successNotice.show();    
    }
}

String.prototype.ucfirst = function() {
    return this.charAt(0).toUpperCase() + this.slice(1);
}

The showNotice function will take two arguments.

  • The type of message to show
  • The data to show in the message.

If the type is 'error' , we hide the success message, loop through the data (which should be an array), and append the list elements to the error notices UL . We then show the error notice using the jQuery function show() . Because all of our code is contained in the same block, we have access to variables set outside this function (successNotice and errorNotice ). If we want to show the success message, we simply hide the error message and display the success message.

With the ucfirst() function, I am adding this function to the prototype of the string object.

"A prototype is an object from which other objects inherit properties."

This means that all string objects will inherit our ucfirst() funkce. This is why, earlier, we used name.ucfirst(). name is a string, and because our method is in the prototype, it is available for us to use.

We get the first character ( charAt(0) ), make it uppercase ( toUpperCase() ), then return it with the rest of the string minus the first character ( slice(1) ). charAt, toUpperCase and slice are all methods of the string object. You can read more about the prototype object here or here.

Now that we have our miscellaneous functions sorted out, we can concentrate on the logic for the form's outcome. We are back to working inside the formSubmitButton.bind logic.

//if form is not valid
if(!formok){
    
    //show error message here
    
}
//if form is valid
else {
    
    //ajax request + show success message here
    
}

We will start with the logic if the form is not valid. The following code should be placed inside the if statement:

//animate required field notice
$('#req-field-desc')
    .stop()
    .animate({
        marginLeft: '+=' + 5
    },150,function(){
        $(this).animate({
            marginLeft: '-=' + 5
        },150);
    });

//show error message 
showNotice('error',errors);

The first chunk of code simply animates the '* indicates a required field'. This is not essential; it's just a nicety that gives the user a bit more feedback -- that a problem has, in fact, occurred. We are using the jQuery function animate() to animate the margin-left CSS value of the element. After this, we are going to call our showNotice() funkce. We want to show the error message so we pass 'error ' as the first argument, then for the data we pass it the errors array we have been storing our form validation error messages in.

If the form is valid, we need to submit it via AJAX.

loading.show();
$.ajax({
    url: form.attr('action'),
    type: form.attr('method'),
    data: form.serialize(),
    success: function(){
        showNotice('success');
        form.get(0).reset();
        loading.hide();
    }
});

Firstly, we reveal our loading gif to indicate that the form is doing something. We then use the jQuery function ajax() to submit the form to process.php . For the url and type, we are using the jQuery function attr() to get these attributes. For the data, we use the jQuery function serialize() . If the AJAX request was successful, we call our showNotice() function and pass it 'success ' as the first argument. This displays our success message. The last thing we do is reset the form (clear the form fields) and hide the loading gif . All of the JavaScript is now taken care of! Congrats1 You should have ended with your script.js file looking like so:

$(function(){

    //set global variables and cache DOM elements for reuse later
    var form = $('#contact-form').find('form'),
        formElements = form.find('input[type!="submit"],textarea'),
        formSubmitButton = form.find('[type="submit"]'),
        errorNotice = $('#errors'),
        successNotice = $('#success'),
        loading = $('#loading'),
        errorMessages = {
            required: ' is a required field',
            email: 'You have not entered a valid email address for the field: ',
            minlength: ' must be greater than '
        }
    
    //feature detection + polyfills
    formElements.each(function(){

        //if HTML5 input placeholder attribute is not supported
        if(!Modernizr.input.placeholder){
            var placeholderText = this.getAttribute('placeholder');
            if(placeholderText){
                $(this)
                    .addClass('placeholder-text')
                    .val(placeholderText)
                    .bind('focus',function(){
                        if(this.value == placeholderText){
                            $(this)
                                .val('')
                                .removeClass('placeholder-text');
                        }
                    })
                    .bind('blur',function(){
                        if(this.value == ''){
                            $(this)
                                .val(placeholderText)
                                .addClass('placeholder-text');
                        }
                    });
            }
        }
        
        //if HTML5 input autofocus attribute is not supported
        if(!Modernizr.input.autofocus){
            if(this.getAttribute('autofocus')) this.focus();
        }
        
    });
    
    //to ensure compatibility with HTML5 forms, we have to validate the form on submit button click event rather than form submit event. 
    //An invalid html5 form element will not trigger a form submit.
    formSubmitButton.bind('click',function(){
        var formok = true,
            errors = [];
            
        formElements.each(function(){
            var name = this.name,
                nameUC = name.ucfirst(),
                value = this.value,
                placeholderText = this.getAttribute('placeholder'),
                type = this.getAttribute('type'), //get type old school way
                isRequired = this.getAttribute('required'),
                minLength = this.getAttribute('data-minlength');
                
            //if HTML5 formfields are supported            
            if( (this.validity) && !this.validity.valid ){
                formok = false;
                
                //if there is a value missing
                if(this.validity.valueMissing){
                    errors.push(nameUC + errorMessages.required);    
                }
                //if this is an email input and it is not valid
                else if(this.validity.typeMismatch && type == 'email'){
                    errors.push(errorMessages.email + nameUC);
                }
                
                this.focus(); //safari does not focus element an invalid element
                return false;
            }
            
            //if this is a required element
            if(isRequired){    
                //if HTML5 input required attribute is not supported
                if(!Modernizr.input.required){
                    if(value == placeholderText){
                        this.focus();
                        formok = false;
                        errors.push(nameUC + errorMessages.required);
                        return false;
                    }
                }
            }

            //if HTML5 input email input is not supported
            if(type == 'email'){     
                if(!Modernizr.inputtypes.email){ 
                    var emailRegEx = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/; 
                     if( !emailRegEx.test(value) ){    
                        this.focus();
                        formok = false;
                        errors.push(errorMessages.email + nameUC);
                        return false;
                    }
                }
            }
            
            //check minimum lengths
            if(minLength){
                if( value.length < parseInt(minLength) ){
                    this.focus();
                    formok = false;
                    errors.push(nameUC + errorMessages.minlength + minLength + ' charcters');
                    return false;
                }
            }
        });
        
        //if form is not valid
        if(!formok){
            
            //animate required field notice
            $('#req-field-desc')
                .stop()
                .animate({
                    marginLeft: '+=' + 5
                },150,function(){
                    $(this).animate({
                        marginLeft: '-=' + 5
                    },150);
                });
            
            //show error message 
            showNotice('error',errors);
            
        }
        //if form is valid
        else {
        	loading.show();
            $.ajax({
                url: form.attr('action'),
                type: form.attr('method'),
                data: form.serialize(),
                success: function(){
                    showNotice('success');
                    form.get(0).reset();
                    loading.hide();
                }
            });
        }
        
        return false; //this stops submission off the form and also stops browsers showing default error messages
        
    });

    //other misc functions
    function showNotice(type,data)
    {
        if(type == 'error'){
            successNotice.hide();
            errorNotice.find("li[id!='info']").remove();
            for(x in data){
                errorNotice.append('<li>'+data[x]+'</li>');    
            }
            errorNotice.show();
        }
        else {
            errorNotice.hide();
            successNotice.show();    
        }
    }
    
    String.prototype.ucfirst = function() {
        return this.charAt(0).toUpperCase() + this.slice(1);
    }
    
});

Conclusion

Gratulujeme! You've made it. It's been a long ride, and we've covered a lot of ground in this tutorial.

So, where do you go from here? This could be expanded to a much larger form, and all the code you've written will still work flawlessly. You could even add in your own validation for things like the telephone input field or the maxlength attribute!

Thanks for reading, and I hope you have enjoyed this tutorial!

If you're looking for a quick starting point, have a look through our gallery of HTML5 Templates, as a quality theme from ThemeForest may be just what your next project needs.