[Tutorial] Viết chức năng thêm, bớt text field nhập liệu với jQuery

Khi xây dựng những hệ thống, ví dụ như e-learning, bạn có thể sẽ bắt gặp chức năng nhập câu hỏi cho câu trả lời, thêm hoặc bớt số lượng câu hỏi, chọn câu trả lời đúng từ danh sách đã nhập rồi nhấn submit để lưu vào cơ sở dữ liệu. Dưới đây mình sẽ chia sẻ cách xây dựng một phần chức năng đó, sử dụng HTML, CSS và thư viện jQuery.

Trước hết là demo tính năng:

Tiếp theo, mình sẽ chuyển sang phần viết code. Tất cả các file mình sẽ đặt vào một thư mục đã có sẵn file thư viện jquery.js.

File index.html

File này có nhiệm vụ dựng ra giao diện mặc định gồm 3 ô nhập liệu:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>Add and remove text field with jQuery</title>
  <link rel="stylesheet" type="text/css" href="style.css">
  <script type="text/javascript" src="jquery.js"></script>
  <script type="text/javascript" src="script.js"></script>
</head>

<body>
  <a href="javascript:void(0)" id="add">Add answer</a>

  <div id="answer">
    <div class="item">
      <label>
        <span>Ans 1</span>
        <input type="text">
        <input type="checkbox" disabled="disabled">
      </label>
      <a href="javascript:void(0)" class="del">del</a>
    </div>
    <div class="item">
      <label>
        <span>Ans 2</span>
        <input type="text">
        <input type="checkbox" disabled="disabled">
      </label>
      <a href="javascript:void(0)" class="del">del</a>
    </div>
    <div class="item">
      <label>
        <span>Ans 3</span>
        <input type="text">
        <input type="checkbox" disabled="disabled">
      </label>
      <a href="javascript:void(0)" class="del">del</a>
    </div>
  </div>

  <input type="button" name="" value="create question" id="create">
  <br>
  <div id="result"></div>
</body>
</html>

Ở trong cặp thẻ <head></head> mình có ghi đường dẫn đến các file style.css và script.js mà chúng ta sẽ xây dựng tiếp sau đây.

File style.css

Mình viết một ít css để tạo giao diện và hiệu ứng nhấp nháy cho phần div có id là "result":

#answer {
  margin: 20px 0px;
}

.item {
  margin: 5px 0px;
}

input:focus {
  outline: 0;
}

#result {
  margin-top: 10px;
  background: pink;
  display: inline-block;
  padding: 0 10px;
  min-width: 200px;
}

.blink_me {
  -webkit-animation-name: blinker;
  -webkit-animation-duration: 1s;
  -webkit-animation-timing-function: linear;

  -moz-animation-name: blinker;
  -moz-animation-duration: 1s;
  -moz-animation-timing-function: linear;

  animation-name: blinker;
  animation-duration: 1s;
  animation-timing-function: linear;
}

@-moz-keyframes blinker {
  0% { opacity: 1.0; }
  50% { opacity: 0.0; }
  100% { opacity: 1.0; }
}

@-webkit-keyframes blinker {
  0% { opacity: 1.0; }
  50% { opacity: 0.0; }
  100% { opacity: 1.0; }
}

@keyframes blinker {
  0% { opacity: 1.0; }
  50% { opacity: 0.0; }
  100% { opacity: 1.0; }
}

File script.js

File này có vai trò quan trọng để tạo nên chức năng của ứng dụng:

$(document).ready(function(){
  // đưa con trỏ chuột vào text field đầu tiên
  $("#answer .item:first input[type='text']").focus();

  // hàm đếm số lượng text field đang có trên màn hình
  function countItem(){
    var items = $("#answer").children().length;
    return items;
  }

  // kích hoạt nút checkbox tương ứng khi nhập liệu cho text field
  // nếu xoá hết ký tự trong text field thì lại vô hiệu hoá checkbox
  $(document).on("keyup", "input[type='text']", function(){
    $(this).next("input[type='checkbox']").removeAttr("disabled");
    if ($(this).val() == "") {
      $(this).next("input[type='checkbox']").attr("disabled", "disabled").removeAttr("checked");
    }
  });

  // thêm text field, giới hạn chỉ có tối đa 10 cái
  $("#add").click(function(){
    var n = countItem();
    if (n == 10) {
      alert("Number of answers isn't greater than 10");
    } else {
      n++;
      $("#answer").append("<div class='item'><label><span>Ans "+n+"</span> <input type='text'> <input type='checkbox' disabled='disabled'></label> <a href='javascript:void(0)' class='del'>del</a></div>");
    }
  });

  // xoá text filed khi click vào nút del ở dòng tương ứng
  // với text file đang có dữ liệu thì không cho xoá
  $(document).on("click", "a.del", function(){
    var n = countItem();
    if (n == 2) {
      alert("Number of answers isn't less than 2");
    } else {
      var check = $(this).siblings().find("input").val();
      // cách viết khác
      // var check = $(this).parent().find("label input").val();
      if (check != "") {
        alert("Cannot delete answer field has content");
      } else {
        $(this).parent().remove();
        for (i=0; i<n-1; i++) {
          $("#answer .item:eq("+i+") label span").html("Ans "+(parseInt(i)+1));
        }
      }
    }
  });

  // nếu lựa chọn checkbox thì đánh dấu đây là câu trả lời đúng
  // nếu bỏ chọn thì không đánh dấu nữa
  $(document).on("change", "input[type='checkbox']", function(){
    var v = $(this).prop("checked");
    if (v == true) {
      $(this).attr("checked", "checked");
    } else {
      $(this).removeAttr("checked");
    }
  });

  // đưa ra màn hình kết quả nhập liệu
  $("#create").bind("click", function(){
    var n = countItem();
    var result = "";
    var count = 0; // số lượng text field đã nhập liệu
    // ghi nhận nội dung các text field, lưu vào biến result
    for (i=0; i<n; i++) {
      var text = $("#answer .item:eq("+i+") label input[type='text']").val();
      if (text != "") {
        count++;
        if ($("#answer .item:eq("+i+") label input[type='checkbox']").prop("checked") == true) text = text + " ---> right!";
        result = result + "<p>Ans "+count+": " + text + "</p>";
      }
    }

    // thêm class "blink_me" để tạo hiệu ứng nhấp nháy cho vùng div chứa kết quả khi nó hiển thị lần đầu tiên
    $("#result").addClass("blink_me");
    if (result == "") {
      // hiển thị thông báo tương ứng nếu chưa nhập liệu cho ít nhất 1 text field
      result = "You haven't input any answer yet!";
      $("#answer .item:first input").focus();
    } else {
      // đếm số câu trả lời đúng
      var ra = $("#answer input[checked='checked']").length;
      if (ra == 0) {
        result = "Please choose at least one right answer";
      } else if (ra == count) {
        result = "Number of right answers must less than number of all answers";
      } else {
        // tất cả đều hợp lệ, hiển thị danh sách lựa chọn ra màn hình
        $("#result").removeClass("blink_me");
        $("input[type='checkbox']").attr("disabled", "disabled").removeAttr("checked");
        $("input[type='text']").val("");
      }
    }
    // gán kết quả vào vùng div có id là "result"
    $("#result").html(result);
  });
});

Như vậy là đã xong, chúng ta sẽ save 3 file lại và chạy để xem kết quả. Mặc dù "mớ spaghetti" ở trên chưa phải là tối ưu nhưng mình cũng hi vọng bài viết này sẽ giúp ích. Cảm ơn các bạn đã đón đọc. (thankyou)