Formularz kontaktowy

Poniższy tekst będzie w zasadzie podsumowaniem tego, co sobie powiedzieliśmy w poprzednich rozdziałach. Naszym celem będzie stworzenie w pełni działającego dynamicznego formularza kontaktowego.

HTML i CSS

Zaczynamy od prostego kodu HTML i CSS, który przewijał nam się już w poprzednich dyskusjach:

Pokaż HTML Pokaż CSS#

Początkowe kroki

Pierwsze czynności będą podobne jak w przypadku poprzednich 2 rozdziałów, czyli pobierzemy formularz, pola do walidacji, wyłączymy domyślne dymki walidacji, a następnie podepniemy odpowiednie zdarzenia:

const form = document.querySelector("#contactForm");
const fields = form.querySelectorAll("[required]");
const formMessage = form.querySelector(".form-message");

//wyłączam validationApi by nie przeszkadzało
form.setAttribute("novalidate", true);

//dodaję dynamiczną walidację pól
for (const field of fields) {
    field.addEventListener("input", () => field.classList.toggle("is-invalid", !field.checkValidity()));
}

form.addEventListener("submit", e => {
    ...
});

Samą wysyłkę napiszemy jako oddzielną funkcję, która przed wysłaniem danych sprawdzi wszystkie pola:

Wysyłka formularza

Żeby wysłać dane, musimy pobrać wszystkie dane z formularza. Wystarczy do tego użyć formData:

Przed samym wysłaniem danych wyłączmy przycisk submit poprzez dodanie do niego atrybutu disabled i odpowiedniej klasy. Dzięki temu zniecierpliwiony użytkownik nie będzie mógł klikać w przycisk wysyłania aż do czasu zakończenia poprzedniej wysyłki.

Dane chcemy wysyłać dynamicznie bez przeładowania strony. Zastosujemy do tego fetch. Napiszmy do tego oddzielną funkcję:

Po stronie serwera

Formularz wysłaliśmy na serwer. Do naszych celów użyjemy PHP, ale podobne działanie można utworzyć w każdej innej technologii serwerowej:

Jest to prosty skrypt, który kolejno sprawdza przesłane pola. Jeżeli dane są poprawne, skrypt spróbuje wysłać maila.

Zwrócone do Javascript dane mogą być w 3 postaciach:

  • {status: "success"} - gdy wszystko poszło dobrze i wiadomość została wysłana

  • {status: "error"} - dane z formularza były poprawne, ale z jakiegoś powodu nie udało się wysłać wiadomości

  • {"errors" : ["name", "email", "message"] } - tablica zawierająca nazwy pól, które zostały wysłane z formularza z błędnymi danymi

Czasami mogą się pojawić problemy z wysyłką maila z naszego serwera. Może to być spowodowane wieloma czynnikami. Niektóre serwery wymagają by nagłówek From wskazywał na maila, który mamy podpięty pod dany serwer. Inne wymagają dodatkowych parametrów. A i nie zawsze będziemy korzystać przecież z PHP. Może w naszym przypadku lepiej sprawdzi się nodemailer? A nawet czasami nie potrzeba w ogóle skryptów na serwerze. Zawsze możemy skorzystać z usług darmowych dostawców statycznych formularzy, które to serwisy wyślą takie maile za nas. Dobre zestawienie znajdziesz pod adresem https://css-tricks.com/a-comparison-of-static-form-providers/

Odpowiedź z serwera

Serwer dostał dane, obsłużył je i zwraca nam odpowiedź w 3 wariantach.

Gdy w odpowiedzi dostaniemy zmienną errors, zakładamy, że będzie to tablica z nazwami błędnie wypełnionych pól. Każdą wartość tej tablicy (linie 17-18) zmieniamy za pomocą map na tablicę selektorów CSS np. [name="email"], [name="message"]. Następnie taką tablicę łączymy za pomocą join(","), dzięki czemu uzyskujemy zapis:

Zastosujmy powyższą logikę w naszej funkcji i odpalmy ją w funkcji wysyłającej formularz:

Odpowiedź z serwera, błąd serwera

Gdy dostajemy odpowiedź, odpalamy funkcję afterSubmit(), która w zależności od zwróconego statusu odpala funkcje showSubmitError() (linia 10 w powyższym listingu) lub showSubmitSuccess() (linia 13).

Dla statusu "error", możemy dodać do formularza tekst z ogólnym komunikatem o błędzie:

Tą samą funkcję możemy dodatkowo użyć, by wyświetlić błędy dla samego fetch (np. gdy występuje brak połączenia, albo adres wysyłki jest błędny):

Odpowiedź z serwera, wreszcie pozytywnie

Zajmijmy się teraz pozytywną odpowiedzią. Możemy tutaj oczywiście wstawiać dynamicznie tekst tak samo, jak powyżej w przypadku błędów. Ja zazwyczaj po pozytywnej wysyłce zastępuję cały formularz nową zawartością. Dzięki temu będzie on trochę bardziej odporny na proste ataki:

Prosty antyspam

Problem z formularzami takimi jak powyższy jest taki, że bardzo lubią je roboty rozsyłające spam. Aby im przeszkodzić, musimy jakoś zabezpieczyć nasze dzieło. Jedną z łatwiejszych metod jest tak zwany honeypot. Metoda ta polega na dodaniu do formularza dodatkowego pola, które ukrywamy za pomocą styli:

Większość robotów ignoruje style, ani nie rozumie języka pisanego, więc wypełnią to pole. Wystarczy teraz po stronie serwera sprawdzić, czy pole to ma wartość. Jeżeli ma, przerywamy wysyłkę, ewentualnie pokrzepiając robota miłymi słowami wiadomości w formie sukcesu:

Recaptcha

Powyższy sposób nie jest idealny i bardzo łatwo można go obejść. Głupi robot może i wypełni powyższe pole, ale użytkownik bandyta nie musi.

Mimo wszystko w realnych projektach warto skorzystać z Recaptchy. Wersja 3 jest niewidoczna dla użytkownika (nie trzeba klikać jakiś dziwnych obrazków), a i jest bardzo łatwa do zaimplementowania.

Po pierwsze musimy wejść na stronę https://developers.google.com/recaptcha. Następnie na górze strony wchodzimy w Recaptcha v3 admin console. Po wejściu w link musimy podać etykietę (nazwa porządkowa), wybrać wersję recaptchy (v3) oraz domenę (adres) naszej strony. Po przejściu dalej dostaniemy 2 klucze. Jeden do użycia w kodzie html/js strony, a drugi do użycia po stronie serwera (np. w kodzie php).

Wystarczy potem postępować zgodnie z punktami z tej odpowiedzi.

Przykładowa implementacja tego rozwiązania w naszym kodzie może mieć postać:

Po stronie serwera:

Last updated