javascriptangularjscheckboxmd-select

AngularJS: How can I select multiple checkboxes using shift and mouse click?


Is it possible to use shift and mouse click to select multiple elements on a table using AngularJS?

I have a table in which the first column is a checkbox and I would like to use SHIFT key and mouse click in order to select multiple rows continuously and can do things like delete, edit them etc.

Example by steps:

  1. Click on 1st row's checkbox.
  2. Hold down SHIFT key.
  3. Click on 10th row's checkbox.

Result: the first 10 rows will be selected.

Does anyone know how this can be done using AngularJS?


Solution

  • I had a similar requirement. And while it's true that the proper way to update the checkboxes is by directly updating the model I wanted a more general solution.

    So I built a pair of directives so I can reuse it on any checkbox list. Basically you wrap all the checkboxes with <multi-checkbox-container> and then add a multi-checkbox attribute to each checkbox. The code does the rest. Simple and easy.

    angular
      .module('app', [])
      .controller('MainController', function($scope) {
        var vm = this;
    
        $scope.checks = {};
        $scope.botigues = [1, 2, 3, 4, 5, 6];
    
      })
      .component('multiCheckboxContainer', {
        controller: function () {
          var ctrl = this;
          var checkboxes = [];
          var checkboxModels = [];
          var previousClickedCheckbox = null;
          
          ctrl.addCheckbox = addCheckbox;
          ctrl.onCheckboxClick = onCheckboxClick;
          
          function addCheckbox(checkbox, checkboxModelCtrl) {
            checkboxes.push(checkbox);
            checkboxModels.push(checkboxModelCtrl);
          }
          
          function onCheckboxClick(checkbox, shiftKey) {
            var start, end, i, checking;
            if (shiftKey && previousClickedCheckbox) {
              checking = checkbox.prop('checked')
              start = checkboxes.indexOf(previousClickedCheckbox);
              end = checkboxes.indexOf(checkbox);
              if (start > end) {
                start = start + end;
                end = start - end;
                start = start - end;
              }
              for (i = start; i <= end; i++) {
                checkboxes[i].prop('checked', checking);
                checkboxModels[i].$setViewValue(checking);
              }
            }
            previousClickedCheckbox = checkbox;
          }
        }
      })
      .directive('multiCheckbox', function () {
        return {
          restrict: 'A',
          require: ['^^multiCheckboxContainer', 'ngModel'],
          link: function (scope, element, attrs, controllers) {
            var containerCtrl = controllers[0];
            var ngModelCtrl = controllers[1];
            containerCtrl.addCheckbox(element, ngModelCtrl);
            
            element.on('click', function (ev) {
              containerCtrl.onCheckboxClick(element, ev.shiftKey);
            });
          }
        };
      });
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular.min.js"></script>
    <div ng-app="app" ng-controller="MainController as vm">
      <multi-checkbox-container>
        <div ng-repeat="botiga in botigues">
          <input type="checkbox" multi-checkbox ng-model="checks[botiga]">
          <label>Botiga {{botiga}}</label>
        </div>
      </multi-checkbox-container>
      <p>checks = {{ checks }}</p>
    </div>