jeremy
jeremy

Reputation: 433

Select All Checkbox for Smart tables in AngularJS

Hey guys so i'm trying to implement a selectall checkbox at the top of my list of checkboxes using a custom directive and i've referred to this thread to do so: https://github.com/lorenzofox3/Smart-Table/issues/270

So far I'm getting an error that says TypeError: Cannot read property 'forEach' of undefined. Would really appreciate it if someone can help me out with this one. Thanks

My html:

<div class="row">
      <div class="col-md-12">
        <table id="document-table" st-table="documents" class="table">
          <thead>
            <tr>
              <th>
                <st-select-all all="yourDisplayedCollection"></st-select-all>
              </th>
            </tr>
          </thead>
          <tbody>
            <tr ng-repeat="document in documents">
              <td><input type="checkbox" ng-model="checkedDocument"/></td>
            </tr>
          </tbody>
         </table>
      </div>
    </div>

My Directive:

.directive('stSelectAll', function () {
        return {
            restrict: 'E',
            template: '<input type="checkbox" ng-model="isAllSelected" />',
            scope: {
            all: '='
            },
            link: function (scope, element, attr) {

            scope.$watch('isAllSelected', function () {
                scope.all.forEach(function (val) {
                val.isSelected = scope.isAllSelected;
                })
            });

            scope.$watch('all', function (newVal, oldVal) {
                if (oldVal) {
                oldVal.forEach(function (val) {
                    val.isSelected = false;
                });
                }

                scope.isAllSelected = false;
            });
            }
        }
        });

Upvotes: 0

Views: 2626

Answers (3)

Akshara Hegde
Akshara Hegde

Reputation: 1

In your javascript, modify your directive as

function rowSelectAll() {
    return {
        require: '^stTable',
        $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('selectedItems', function(newVal) {
                var s = newVal.length;
                var a = ($scope.all !== undefined) ? $scope.all.length : 0;
                if ((s == a) && s > 0 && a > 0) {
                    element.find('input').prop('checked', true);
                    scope.isAllSelected = false;
                } else {
                    element.find('input').prop('checked', false);
                    $scope.isAllSelected = true;
                }
            });
        }
    };
}
app.directive('rowSelectAll', rowSelectAll);

And in HTML file, inside table header use your directive and assign table collection i.e, displayedCollection to it.

<th row-select-all="displayedCollection" selected-items="selected_items" ng-click="selectAll(displayedCollection)"><input type="checkbox" ng-disabled="displayedCollection.length == 0"></th>

if you want to selected elements then use the following code:

    $scope.selected_items = [];
    // Function to get data for all selected items
    $scope.selectAll = function (collection) {
        // if there are no items in the 'selected_items' array, push all elements to 'selected_items'.
        if ($scope.selected_items.length === 0) {
            angular.forEach(collection, function(val) {
                if (val.bank_flag) {
                    $scope.selected_items.push(val);
                }
          });

        // if there are items in the 'selected_items' array, add only those that are not.
        } else if ($scope.selected_items.length > 0 && $scope.selected_items.length != $scope.displayedCollection.length) {
            angular.forEach(collection, function(val) {

                var found = $scope.selected.indexOf(val);
                if(found == -1) {
                    $scope.selected_items.push(val);
                }

            });
        // Otherwise, reinitiate the variable.
        } else  {
            $scope.selected_items = [];
        }
    };

Upvotes: 0

Pop-A-Stash
Pop-A-Stash

Reputation: 6652

I don't think you need to watch all, only isAllSelected. Try removing that watch altogether. I'm using the same directive for Smart Table and I don't watch all. You also want to add a check to make sure all exists:

scope.$watch('isAllSelected', function() {
  if(scope.all) {
    scope.all.forEach(function (val) {
      val.isSelected = scope.isAllSelected;
    }
  }
});

Also, you are supposed to make a copy of your original array to use for st-safe-src attribute on your table. Then use the original array for your directive.

// in your controller (not in your directive)
$scope.yourDisplayedCollection = [].concat($scope.documents);

Then change your view.

<table id="document-table" st-table="documents" st-safe-src="yourDisplayedCollection" class="table">

<st-select-all all="documents"></st-select-all>

Upvotes: 1

nham
nham

Reputation: 161

 all  <input type="checkbox" ng-click="ctrl.toggleAll(ctrl.all)" ng-model="ctrl.all">
 a    <input type="checkbox" ng-model="ctrl.checks.alpha" ng-value="allChecked">
 b    <input type="checkbox" ng-model="ctrl.checks.beta" ng-value="allChecked">

script

function MyController() {
    this.data = [
        {title: 'a', data: [1,2,3]},
        {title: 'b', data: [4,5,6]},
        {title: 'c', data: [7,8,9]}
    ];

    let ctrl = this;

    ctrl.checks = {
       alpha: false,
       beta: false
    };

    ctrl.toggleAll = function(toggle) {
        for (let check in ctrl.checks) {
            ctrl.checks[check] = toggle;
        }
   };
   return this;
}
angular.module('test').controller('MyController',MyController);

All of the children checkboxes will assume the state of the parent checkbox in this implementation. Rather than simply toggling the prior state of the child checkbox.

Enjoy. It's has been tested, but feel free to ask if it's broken or you have questions.

Upvotes: 0

Related Questions