Chúng ta thích thú cái đẹp của con bướm, nhưng hiếm khi ưa những thay đổi mà nó đã trải qua để đạt được vẻ đẹp đó.

Maya Angelou

FORM TRONG HTML


Form trong HTML

Phần tử form

Các form được thêm tới trang web bằng phần tử form. Phần tử form là một bộ chứa mọi nội dung của form, bao gồm các form control như các trường văn bản và nút. Nó cũng có thể chứa các phần tử khối (như h1, p, danh sách). Tuy nhiên, nó không thể chứa phần tử form khác.

Ví dụ, tài liệu HTML sau có chứa một form:

<!DOCTYPE html>
<html>
  <head>
    <title>Mailing List Signup</title>
    <meta charset="utf-8">
  </head>
  <body>
    <h1>Mailing List Signup</h1>

    <form action="/mailinglist.php" method="POST">
      <fieldset>
        <legend>Join our email list</legend>
        <p>
          Get news about the band such as tour dates and special MP3 releases sent to your own in-box.
        </p>
        <ol>
          <li>
            <label for="firstlast">Name:</label>
            <input type="text" name="fullname" id="firstlast">
          </li>
          <li>
            <label for="email">Email:</label>
            <input type="text" name="email" id="email">
          </li>
        </ol>
        <input type="submit" value="Submit">
      </fieldset>
    </form>
  </body>
</html>

Thường thì ta nên bọc các form control trong các phần tử HTML như một danh sách hoặc một div. Danh sách có thứ tự như ví dụ trên, là một giải pháp phổ biến. Các phần tử fieldset, legendlabel được sử dụng trong ví dụ trên nhằm tăng khả năng tiếp cận. Chúng sẽ được giải thích sau trong bài này.

Thuộc tính action

Thuộc tính action cung cấp địa chỉ URL tới ứng dụng, hoặc script được dùng để xử lý form. Thuộc tính action trong ví dụ trên gửi dữ liệu tới một script có tên mailinglist.php:

<form action="/mailinglist.php" method="POST">...</form>

Phần mở rộng .php cho biết rằng script này viết bằng ngôn ngữ PHP. Ngoài ra script còn có thể viết bằng nhiều ngôn ngữ khác như Java, JavaScript, Python, Ruby…

Thuộc tính method

Thuộc tính method xác định cách thông tin được gửi tới máy chủ. Giả sử bạn nhập vào hai trường NameEmail thông tin như sau:

Có hai cách gửi thông tin tới máy chủ: POSTGET, xác định bởi giá trị của thuộc tính method trong phần tử form. Nếu không chỉ định rõ giá trị của method thì phương thức GET mặc định được sử dụng.

Phương thức GET

<form action="https:///www.bandname.com/mailinglist.php" method="GET">...</form>

Khi bạn bấm nút Submit, trình duyệt chuyển đến URL có dạng:

https://www.bandname.com/mailinglist.php?fullname=Sally+Strongarm&email=strongarm%40example.com

Như vậy với GET thông tin sau được gửi kèm theo URL:

fullname = Sally Strongarm
email = strongarm@example.com

Trong đó fullnameemail lấy từ giá trị của thuộc tính name của các trường NameEmail.

Trước khi gửi thông tin được mã hóa, cách dấu cách thay thế bằng dấu cộng +, kí tự @ được thay bằng %40.

fullname = Sally Strongarm

được mã hóa thành:

fullname=Sally+Strongarm
email = strongarm@example.com

được mã hóa bằng:

email=strongarm%40example.com

Sau đó chúng được nối với nhau, ngăn cách bởi dấu &:

fullname=Sally+Strongarm&email=strongarm%40example.com

và đặt sau URL của script theo sau dấu ?.

Phương thức POST

Khi phương thức method được đặt thành POST, trình duyệt gửi một request tới máy chủ chứa các header đặc biệt, sau đó là thông tin lấy được từ form. Về lý thuyết chỉ máy chủ có thể xem được các thông tin này, do vậy phương thức POST phù hợp khi cần gửi các thông tin nhạy cảm như địa chỉ nhà hay các thông tin cá nhân khác.

Phương thức POST cũng thích hợp khi cần gửi nhiều dữ liệu, do số ký tự không bị giới hạn như GET.

Thuộc tính name

Mỗi form control bắt buộc phải có thuộc tính name. Giá trị name đóng vai trò như tên biến tương ứng với mỗi trường dữ liệu, dữ liệu thu được được gán cho biến này.

Trong ví dụ sau, văn bản lấy được từ phần tử textarea được lưu vào biến có tên comment:

<textarea name="comment" rows="4" cols="45" placeholder="Leave us a comment."></textarea>

Khi người dùng nhập văn bản (bình luận) vào trường này (chẳng hạn This is the best band ever!), nó được truyền tới máy chủ như cặp biến/giá trị sau:

comment=This+is+the+best+band+ever%21

Các form control không liên quan đến việc thu thập dữ liệu như nút SubmitReset không cần phải có thuộc tính name.

Các form control

Phiên bản HTML5.2 có 22 form control. Phần này ta sẽ tìm hiểu chúng.

Các form control để thu thập văn bản

Một trong những công việc phổ biến nhất của form là thu thập thông tin dưới dạng văn bản. Sử dụng form control nào để thu thập dữ liệu văn bản phụ thuộc vào chuỗi văn bản cần thu thập gồm một dòng hay nhiều dòng.

Thu thập một dòng văn bản

Để thu thập văn bản viết trên một dòng, sử dụng phần tử input với thuộc tính typetext.

<li>
  <label>
    Favorite color:
    <input type="text"
           name="favcolor"
           value="Red"
           maxlength="50">
  </label>
</li>

Có thêm vài thuộc tính bạn cần biết:

  • value: cung cấp giá trị mặc định của trường. Giá trị này cũng tự động được hiển thị khi form được tải. Khi bạn reset form, nó trả về giá trị này. Có một thuộc tính khác là placeholder cung văn bản mô tả cho trường, chẳng hạn “My favorite color”. Giá trị của placeholder không phải là giá trị của trường.
  • maxlength, minlength: Mặc định người dùng có thể nhập vô hạn ký tự. Bạn có thể cài đặt số kí tự tối đa được nhập qua thuộc tính maxlength, số kí tự tối thiểu cần nhập qua thuộc tính minlength.
  • size: xác định chiều dài của trường, là số kí tự tối đa trường có thể hiện thị được.

Thu thập một đoạn văn bản

Để thu thập một đoạn văn bản (gồm nhiều dòng), sử dụng phần tử textarea. Không giống như phần tử input, bạn có thể đặt nội dung vào giữa thẻ mở và thẻ đóng của phần tử textarea. Nội dung này trở thành giá trị mặc định của trường, được hiển thị khi form được tải.

<p>
  <label>
    Official contest entry: <br>
    <em>Tell us why you love the band. Five winners will get backstage passes!</em><br>
    <textarea name="contest_entry" rows="5" cols="50">
      The band is totally awesome!
    </textarea>
  </label>
</p>

Thuộc tính rowscols cho phép xác định kích thước của textarea, rows xác định số dòng văn bản textarea hiển thị được, cols xác định số kí tự trên một dòng mà textarea có thể hiển thị được. Khi textarea không thể hiển thị được toàn bộ văn bản, các thanh cuộn sẽ xuất hiện.

Thuộc tính maxlengthminlength cài đặt số kí tự tối đa và tối thiểu có thể nhập vào trường.

Thường thì ta không cung cấp giá trị mặc định cho textarea, mà cung cấp một chỉ dẫn qua thuộc tính placeholder:

<p>
  Official contest entry: <br>
  <em>Tell us why you love the band. Five winners will get backstage passes!</em><br>
  <textarea name="contest_entry" placeholder="50 words or less" rows="5" cols="50"></textarea>
</p>

Thuộc tính disablereadonly

Thuộc tính disabledreadonly ngăn người dùng tương tác với một form control, nhưng giữa chúng có một chút khác biệt.

Khi một form control bị disabled, người dùng không thể chọn nó. Trình duyệt thường hiển thị những form control này có dạng màu xám. Muốn “enable” lại cần sử dụng JavaScript.

Khi một form control cài đặt thành readonly, người dùng có thể chọn, nhưng không thể thay đổi giá trị của trường tương ứng.

<p>
  <label>
    Disabled form control:
    <input type="text" name="" value="Default value" disabled>
  </label>
  <br>
  <label>
    Readonly form control:
    <input type="text" name="" value="Default value" readonly>
  </label>
</p>

Khác biệt quan trọng nhất giữa disabledreadonly là các giá trị trường readonly vẫn được gửi đi khi nút Submit được bấm, trong khi trường disabled thì không.

Các form control thu thập văn bản đặc biệt

Thu thập mật khẩu

<li>
  <label for="form-pswd">Password:</label>
  <input type="password" name="pswd" maxlength="12" id="form-pswd">
</li>

Từ khóa tìm kiếm, địa chỉ email, số điện thoại, địa chỉ URL

<li>
  <label for="form-search">Search:</label>
  <input type="search" name="search" id="form-search">
</li>
<li>
  <label for="form-email">Email:</label>
  <input type="email" name="email" id="form-email">
</li>
<li>
  <label for="form-tel">Tel:</label>
  <input type="tel" name="tel" id="form-tel">
</li>
<li>
  <label for="form-url">Url:</label>
  <input type="url" name="url" id="form-url">
</li>

Phần tử datalist

Phần tử datalist cho phép cung cấp danh sách thả xuống chứa các giá trị gợi ý cho một trường văn bản bất kỳ. Nó cho phép người dùng chọn nhanh một số giá trị phổ biến, nhưng nếu không muốn người dùng vẫn có thể nhập một giá trị khác.

Trong datalist chứa nhiều phần tử option. Mỗi một giá trị trong danh sách được đánh tạo bởi phần tử option, giá trị được cung cấp qua thuộc tính value của option.

Mỗi một datalist được gắn với một trường cụ thể. Để khai báo sự tương ứng này, sử dụng thuộc tính id trong datalistlist trong một form control, như sau:

<p>
  Education completed:
  <input type="text" list="edulevel" name="education">

  <datalist id="edulevel">
    <option value="High School">
    <option value="Bachelors Degree">
    <option value="Masters Degree">
    <option value="PhD">
  </datalist>
</p>

Nút Submit và Reset

Nút submit: Gửi dữ liệu từ form tới máy chủ

<input type="submit">

Nút reset: Đặt lại giá trị các form control về mặc định.

<input type="reset">
<p>
  <label for="firstname">First Name:</label>
  <input type="text" name="firstname" id="firstname" value="Hung">
  <br>
  <label for="lastname">Last Name:</label>
  <input type="text" name="lastname" id="lastname" value="Phung">
</p>
<p>
  <input type="submit" value="Submit">
  <input type="reset" value="Start over">
</p>

Nút radio và checkbox

Nút radio

Khi có một danh sách các tùy chọn và bạn chỉ có thể chọn một và chỉ một tùy chọn trong số đó, đó là lúc ta sử dung các nút radio:

<p>How old are you?</p>
<ol>
  <li>
    <input type="radio" name="age" value="under24" checked>
    under 24
  </li>
  <li>
    <input type="radio" name="age" value="25-34">
    25 to 34
  </li>
  <li>
    <input type="radio" name="age" value="35-44">
    35 to 44
  </li>
  <li>
    <input type="radio" name="age" value="over45">
    45+
  </li>
</ol>

Một nút radio được tạo bởi:

<input type="radio">

Khi các nút radio phải có cùng name và bạn chỉ có thể chọn một trong số chúng, giá trị của mỗi nút được xác định bởi thuộc tính value. Nút radio nào có thuộc tính checked sẽ mặc định được chọn.

Trong ví dụ trên các nút radio có cùng tên age, giá trị age được lấy từ thuộc tính value của nút được chọn.

Chặng hạn nếu bạn chọn nút thứ hai “25 to 34” thì:

age = 25-34

Nút checkbox

Khi có một danh sách các tùy chọn và bạn có thể chọn cùng lúc nhiều tùy chọn này, khi đó các nút checkbox được sử dụng.

<p>What type music do you listen to?</p>
<ul>
  <li>
    <input type="checkbox" name="genre" value="punk" checked>
    Punk rock
  </li>
  <li>
    <input type="checkbox" name="genre" value="indie" checked>
    Indie rock
  </li>
  <li>
    <input type="checkbox" name="genre" value="hiphop">
    Hip Hop
  </li>
  <li>
    <input type="checkbox" name="genre" value="rockabilly">
    Rockabilly
  </li>
</ul>

Các menu

Phần tử select tạo một menu thả xuống. Trong menu thả xuống, chỉ một mục có thể chọn (giống như nút radio). Ví dụ:

<p>What is your favorite 80s band?</p>
<select name="EightiesFave">
  <option>The Cure</option>
  <option>Cocteau Twins</option>
  <option>Tears for Fears</option>
  <option>Thompson Twins</option>
  <option value="EBTG">Everything But the Girl</option>
  <option>Depeche Mode</option>
  <option>The Smiths</option>
  <option>New Order</option>
</select>

Khi không có value nội dung của option được gửi tới máy chủ khi nó được chọn. Khi có value thì giá trị của value được gửi tới máy chủ thay cho nội dung của option. Các giá trị này được gán cho biến có tên lấy từ thuộc tính name của select, trong ví dụ trên là biến EightiesFave.

Để biến menu thả xuống thành menu cuộn, đơn giản cài đặt giá trị cho thuộc tính size. Theo mặc định, ta chỉ có thể chọn một mục, muốn chọn nhiều mục cùng lúc (giống nút checkbox), sử dụng thuộc tính multiple.

<p>What is your favorite 80s band?</p>
<select name="EightiesFave" size="6" multiple>
  <option>The Cure</option>
  <option>Cocteau Twins</option>
  <option>Tears for Fears</option>
  <option>Thompson Twins</option>
  <option value="EBTG">Everything But the Girl</option>
  <option>Depeche Mode</option>
  <option>The Smiths</option>
  <option>New Order</option>
</select>

Chú ý, để chọn nhiều mục, ta giữ phím Ctrl trong khi chọn.

Muốn một mục được chọn mặc đinh, sử dụng thuộc tính selected trong phần tử option tương ứng.

Nhóm nhiều mục với nhau

Trong menu thả xuống, có thể có nhiều mục có liên quan về mặt ý nghĩa với nhau, lúc đó ta có thể gom chúng thành một nhóm và gán nhãn cho nhóm bằng phần tử optgroup và thuộc tính label:

<select name="icecream" size="7" multiple>
  <optgroup label="traditional">
    <option>vanilla</option>
    <option>chocolate</option>
  </optgroup>
  <optgroup label="fancy">
    <option>Super praline</option>
    <option>Nut surprise</option>
    <option>Candy corn</option>
  </optgroup>
</select>

Chọn file

Không chỉ dữ liệu văn bản, các form còn có thể truyền các file từ ổ cứng máy tính tới máy chủ.

<form action="/client.php" method="POST" enctype="multipart/form-data">
  <fieldset>
    <label>
      Send a photo to be used as your online icon <em>(optional)</em><br>
      <input type="file" name="photo">
    </label>
  </fieldset>
</form>

Khi sử dụng form để truyền file tới máy chủ, bạn phải chỉ rõ kiểu mã hóa là multipart/form-data trong phần tử form và phải sử dụng phương thức POST.

Kiểu phần tử input có vài thuộc tính mới:

  • accept: chỉ rõ kiểu file nào được chấp nhận.
  • multiple: cho phép chọn nhiều file để truyền.
  • required: bắt buộc phải chọn file.

Các form control ẩn

Đôi khi cần gửi tới máy chủ những thông tin không đến từ người dùng. Lúc này có thể sử dụng các form control ẩn để gửi các thông tin này. Các form control ẩn không được hiển thị trong trình duyệt.

Các form control ẩn được thêm qua phần tử input với typehidden. Mục đích của nó là gửi cặp giá trị tên biến/giá tr tới máy chủ. Ví dụ:

<input type="hidden" name="success-link" value="https://www.example.com/thankyou.html">

Nhập dữ liệu ngày và giờ

<input type="date">

Cú pháp ngày là:

YYYY-MM-DD
  • YYYY: năm (có 4 chữ số)
  • MM: tháng (có 2 chữ số)
  • DD: ngày (có 2 chữ số)
<label>
  Birthday:
  <input type="date" name="date" value="1986-08-03">
</label>

<input type="time">

Cú pháp giờ là:

hh:mm:ss
  • hh: giờ (có 2 chữ số từ 00 đến 23)
  • mm: phút (có 2 chữ số từ 00 đến 59)
  • ss: giây (có 2 chữ số từ 00 đến 59)
<label>
  Time:
  <input type="time" name="time" value="20:30:00">
</label>

<input type="datetime-local">

Cú pháp ngày, giờ (không có múi giờ) là:

YYYY-MM-DDThh:mm:ss

trong đó T là dấu phân cách giữa phần ngày và phần giờ.

<label>
  Date and time:
  <input type="datetime-local" name="datetime" value="2020-02-12T00:38:00">
</label>

<input type="month">

Cú pháp tháng năm:

YYYY-MM
<input type="month" name="month" value="2020-02">

<input type="week">

Cú pháp tuần trong năm:

YYYY-W#

trong đó # là số thứ tự tuần trong năm.

<input type="week" name="week" value="2020-W6">

Nhập dữ liệu số

Nhập một số

<label>
  Number of guests:
  <input type="number" name="guests" min="1" max="6">
</label>

Nhập một số sử dụng thanh trượt

<label>
  Satisfaction (0 to 100)
  <input type="range" name="satisfaction" min="0" max="10" step="1">
</label>

Thuộc tính step cho phép xác định giá trị bước nhảy khi kéo thanh trượt. Mặc định là 1.

Chọn màu

<label>
  Your favorite color:
  <input type="color" name="favcolor" value="#FF0065">
</label>

Giá trị màu có dạng:

#RRGGBB

trong đó RRGGBB là mã Hexa của màu.

Tăng cường tính dễ sử dụng của form

Các phần tử label, fieldsetlegend giúp form dễ sử dụng hơn.

Label

Phần tử label giúp liên kết văn bản mô tả với trường tương ứng. Lúc này khi muốn chọn trường, chỉ cần chọn văn bản mô tả trường đó.

Mỗi phần tử label chỉ tương ứng với một form control duy nhất. Có hai cách sử dụng.

Liên kết ngầm định

Đặt form control trong label:

<ul>
  <li>
    <label>
      <input type="checkbox" name="genre" value="punk">
      Punk rock
    </label>
  </li>
  <li>
    <label>
      <input type="checkbox" name="genre" value="indie">
      Indie rock
    </label>
  </li>
  <li>
    <label>
      <input type="checkbox" name="genre" value="hiphop">
      Hip Hop
    </label>
  </li>
  <li>
    <label>
      <input type="checkbox" name="genre" value="rockabilly">
      rockabilly
    </label>
  </li>
</ul>

Để chọn một nút checkbox chỉ cần click vào văn bản mô tả.

Liên kết tương minh

Kết hợp thuộc tính for (trong label) với id (trong form control):

<label for="form-login-username">Login account</label>
<input type="text" name="login" id="form-login-username">
<br>
<label for="form-login-password">Password</label>
<input type="password" name="password" id="form-login-password">

fieldset và legend

fieldset nhóm các form control có liên quan lại với nhau. Mỗi fieldset có thể có tiêu đề đặt trong phần tử legend.

<fieldset>
  <legend>Mailing List Sign-up</legend>
  <ul>
    <li>
      <label>
        Add me to your mailing list
        <input type="radio" name="list" value="yes" checked>
      </label>
    </li>
    <li>
      <label>
        No thanks
        <input type="radio" name="list" value="no">
      </label>
    </li>
  </ul>
</fieldset>

<fieldset>
  <legend>Customer Information</legend>
  <ul>
    <li>
      <label>
        Full name:
        <input type="text" name="fullname">
      </label>
    </li>
    <li>
      <label>
        Email:
        <input type="email" name="email">
       </label>
     </li>
     <li>
       <label>
         State:
         <input type="text" name="state">
       </label>
     </li>
  </ul>
</fieldset>