Reputation: 433
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
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
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
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