AngularJS Smart-Table select all rows directive

So I’ve been recently working on an app that required the ability for users to select all rows in a table, as well as selecting rows manually. I then realised that such a function had not existed yet for Smart Table Module, so I thought I’d share this with you guys. You’ll also be able the get the data from the selected rows into a $scope, which for some reason, is not yet implemented in Smart-Table.

Smart Table is a table module for AngularJS. It allows you to quickly compose your table in a declarative way including sorting, filtering, row selection and pagination. It’s also lightweight (around 3kb minified) and has no other dependencies than Angular itself.

Firstly, let’s start with the directives. There is one for row slection, which creates the checkbox for every row and assigns the st-selected class and another to select all the rows, to which we pass our table data and it checks it to see which items have isSelected == true

rowSelectAll.js
function rowSelectAll() {

  return {
    require: '^stTable',
    template: '<input type="checkbox">',
    scope: {
      all: '=rowSelectAll',
      selected: '='
    },
    link: function (scope, element, attr) {

      scope.isAllSelected = false;

      element.bind('click', function (evt) {

        scope.$apply(function () {

          scope.all.forEach(function (val) {

            val.isSelected = scope.isAllSelected;

          });

        });

      });

      scope.$watchCollection('selected', function(newVal) {

        var s = newVal.length;
        var a = scope.all.length;

        if ((s == a) && s > 0 && a > 0) {

          element.find('input').attr('checked', true);
          scope.isAllSelected = false;

        } else {

          element.find('input').attr('checked', false);
          scope.isAllSelected = true;

        }

      });
    }
  };
}

angular
  .module('app')
  .directive('rowSelectAll', rowSelectAll)
rowSelect.js
function rowSelect() {
  return {
    require: '^stTable',
    template: '<input type="checkbox">',
    scope: {
        row: '=rowSelect'
    },
    link: function (scope, element, attr, ctrl) {

      element.bind('click', function (evt) {

        scope.$apply(function () {

            ctrl.select(scope.row, 'multiple');

        });

      });

      scope.$watch('row.isSelected', function (newValue) {

        if (newValue === true) {

            element.parent().addClass('st-selected');
            element.find('input').attr('checked', true);

        } else {

            element.parent().removeClass('st-selected');
            element.find('input').attr('checked', false);

        }
      });
    }
  };
}

angular
  .module('app')
  .directive('rowSelect', rowSelect)

Next, in order to get data from the selected rows, I’ve created two functions. selectAll() goes with the rowSelectAll directive and we pass it the entire dataset. select() only needs the row from ng-repeat, being assigned to the single row selection directive.

app.js
function MainCtrl() { 

  var vm = this;
  
  // Declare the array for the selected items
  vm.selected = []; 
  
  // Function to get data for all selected items
  vm.selectAll = function (collection) {
    
    // if there are no items in the 'selected' array, 
    // push all elements to 'selected'
    if (vm.selected.length === 0) {
      
      angular.forEach(collection, function(val) {
        
        vm.selected.push(val.id); 
        
      });
      
    // if there are items in the 'selected' array, 
    // add only those that ar not
    } else if (vm.selected.length > 0 && vm.selected.length != vm.data.length) {
      
      angular.forEach(collection, function(val) {
        
        var found = vm.selected.indexOf(val.id);
        
        if(found == -1) vm.selected.push(val.id);
        
      });
      
    // Otherwise, remove all items
    } else  {
      
      vm.selected = [];
      
    }
    
  };
  
  // Function to get data by selecting a single row
  vm.select = function(id) {
    
    var found = vm.selected.indexOf(id);
    
    if(found == -1) vm.selected.push(id);
    
    else vm.selected.splice(found, 1);
    
  }
}

angular
  .module('app', ['smart-table'])
  .controller('MainCtrl', MainCtrl)

The directives add the st-selected class to every row that is selected, so in order to see the selected row, just style that class.

style.css
.st-selected > td {
  background: aliceblue;
}

See it in action

And that’s it! If you have any questions, let me know in the comments below.