Vse o WEB
Информация и размышления о Web технологиях

Выделение нескольких checkbox с помощью клавиши Shift

Если вы сталкивались с Javascript, работали с jQuery, то обработка событий браузера (таких как onclick, onsubmit и др.) не вызывает у вас вопросов. Представьте, что у вас есть HTML таблица с записями, для которой нужно реализовать обработку действий в пакете, например, удалить выделенные записи или переместить все выделенные статьи в категорию. Первым шагом для этого будет добавление в таблицу чекбоксов. Как реализовать подобный функционал выделения записей мы и поговорим в данной статье.

Для примера возьмем довольно простую HTML разметку:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Обработка кликов на чекбоксах</title>
  </head>
  <body>
    <table border="1" cellspacing="2" cellpadding="10">
      <thead>
        <tr>
          <th><input type="checkbox" id="select-all" class="chkbox" value="1" title="Выделить все" /></th>
          <th>Title</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><input type="checkbox" id="id_chk1" class="chkbox" value="1" /></td>
          <td>Check 1</td>
        </tr>
        <tr>
          <td><input type="checkbox" id="id_chk2" class="chkbox" value="2" /></td>
          <td>Check 2</td>
        </tr>
        <tr>
          <td><input type="checkbox" id="id_chk3" class="chkbox" value="3" /></td>
          <td>Check 3</td>
        </tr>
        <tr>
          <td><input type="checkbox" id="id_chk4" class="chkbox" value="4" /></td>
          <td>Check 4</td>
        </tr>
        <tr>
          <td><input type="checkbox" id="id_chk5" class="chkbox" value="5" /></td>
          <td>Check 5</td>
        </tr>
        <tr>
          <td><input type="checkbox" id="id_chk6" class="chkbox" value="6" /></td>
          <td>Check 6</td>
        </tr>
        <tr>
          <td><input type="checkbox" id="id_chk7" class="chkbox" value="7" /></td>
          <td>Check 7</td>
        </tr>
      </tbody>
    </table>
    
    <!-- scripts -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script>

      <!-- здесь будем добавлять jQuery код  -->

    </script>
  </body>
</html>

 

Обычно в таких случая мы хотим иметь возможность выделять все записи одним кликом. Для этого в хедер таблицы добавлен чекбокс "Выделить все". Напишем простой обработчик кликов для него:

$('#select-all').on('click', function () {

  // находим все чекбоксы
  var $checkboxes = $('.chkbox');
        
  // устанавливаем им свойство checked, такое же, как и чекбокса #select-all
  $checkboxes.prop('checked', $(this).prop('checked'));

});

 

Теперь неплохо бы, чтоб после выделения всех чекбоксов и снятия выделения с одного, чекбокс #select-all также отображался без выделения. И в обратном случае: если все чекбоксы выделяются один за одним, то после выделения всех, чекбокс #select-all также выделялся. На словах сложно, на практике все просто:

$('.chkbox').on('click', function () {
  var $selectAll = $('#select-all');

  // находим все чекбоксы
  var $checkboxes = $('.chkbox');

  // находим все выделенные чекбоксы
  var $allChecked = $checkboxes.filter(':checked');
        
  // сравниваем количество всех и выбранных чекбоксов
  // если равно - выделяем чекбокс #select-all
  // если нет - снимаем выделение с чекбокса #select-all
  $selectAll.prop('checked', $checkboxes.length === $allChecked.length);
});

 

Теперь представьте, что у вас на странице десятки записей (да-да, обычно их меньше благодаря разбиению страницы), а выделить нужно всего 5 или 10, но не все. Выделять поштучно не слишком-то и удобно. И снимать выделение также не удобно. Неплохо бы, чтоб при нажатии Shift мы могли выделять несколько чекбоксов, указывая только начальный и конечный в интервале. Не забываем также, что при выделении через Shift всех чекбоксов, у нас должен выделяться чекбокс #select-all

+var lastChecked = null;
-$('.chkbox').on('click', function () {
+$('.chkbox').on('click', function (e) {

  var $selectAll = $('#select-all');

  // находим все чекбоксы
  var $checkboxes = $('.chkbox');
+
+  // если это первый выделенный чекбокс, сохраняем его как последий выделенный
+  if (!lastChecked) {
+    lastChecked = this;
+  }
+
+  // проверяем, что клавиша Shift нажата
+  if (e.shiftKey) {
+    // находим начало и конец интервала
+    var start = $checkboxes.index(this);
+    var end = $checkboxes.index(lastChecked);
+
+    // фильтруем все чекбоксы по интервалу выделения          
+    $checkboxes.slice(
+      Math.min(start, end),
+      Math.max(start, end) + 1
+    )
+    // выделяем или снимаем выделение с интервала в зависимости
+    // от первого чекбокса в выделении
+    .prop('checked', lastChecked.checked)
+  }
+  
+  // сохраняем последний выделенный чекбокс    
+  lastChecked = this;

  // находим все выделенные чексбоксы
  var $allChecked = $checkboxes.filter(':checked');
        
  // сравниваем количество всех и выбранных чекбоксов
  // если равно - выделяем чекбокс #select-all
  // если нет - снимаем выделение с чекбокса #select-all
  $selectAll.prop('checked', $checkboxes.length === $allChecked.length);
        
 });

 

Полный код обработчиков событий браузера:

<script>
  $('#select-all').on('click', function () {
    // находим все чекбоксы
    var $checkboxes = $('.chkbox');
        
    // устанавливаем им свойство checked, такое же, как и элемента #select-all
    $checkboxes.prop('checked', $(this).prop('checked'));
  });
      
  var lastChecked = null;
  $('.chkbox').on('click', function (e) {
    var $selectAll = $('#select-all');

    // находим все чексбоксы
    var $checkboxes = $('.chkbox');

    // если это первый выделенный чекбокс, сохраняем его как последий выделенный
    if (!lastChecked) {
      lastChecked = this;
    }
        
    // находим начало и конец интервала
    var start = $checkboxes.index(this);
    var end = $checkboxes.index(lastChecked);
        
    // фильтруем все чекбоксы по интервалу выделения          
    $checkboxes.slice(
      Math.min(start, end), 
      Math.max(start, end) + 1
    )
    // выделяем или снимаем выделение с интервала в зависимости
    // от первого чекбокса в выделении
    .prop('checked', lastChecked.checked);
        
    // сохраняем последний выделенный чекбокс
    lastChecked = this;

    // находим все выделенные чексбоксы
    var $allChecked = $checkboxes.filter(':checked');
        
    // сравниваем количество всех и выбранных чекбоксов
    // если равно - выделяем чекбокс #select-all
    // если нет - снимаем выделение с чекбокса #select-all
    $selectAll.prop('checked', $checkboxes.length === $allChecked.length);
        
  });
</script>

 

Надеюсь, статья будет вам полезной. Если есть какие-то вопросы, пишите их в комментариях, не стесняйтесь ;)

Наверх