angularjs select all checkbox function - javascript

I'm fairly new to angular and have a select all checkbox that checks all the boxes through ng-model/ng-checked.
<th>
<input type="checkbox" id="selectAll" ng-model="selectAll"/>
</th>
<th>
${Case Number}
</th>
<tr ng-repeat="item in c.onbCase>
<td><input type="checkbox" name="checkbox" ng-click="checkboxFunc(item)"
ng-model="item.checked"
ng-checked="selectAll || item.checked"/>
</td>
<td>{{item.number}}</td>
</tr>
I also have a function called checkboxFunc that sets item.selected to true if checked and throws the case number into an array:
$scope.onbNum = [];
$scope.checkboxFunc = function(item){
if(item.selected == false) {
if($scope.onbNum.indexOf(item.number)==-1){
$scope.onbNum.push(
item.number
)
}
item.selected = true;
} else {
if($scope.onbNum.indexOf(item.number)!==-1){
var pos = $scope.onbNum.indexOf(item.number);
$scope.onbNum.splice(pos,1)
}
item.selected = false;
}
}
While the Select All checkbox checks all the boxes when clicked upon, how do I fix my function so that all the case numbers get thrown into the array?

Don't use ng-checked and ng-model together on the same element.
From the Docs:
Note that [the ng-checked] directive should not be used together with ngModel, as this can lead to unexpected behavior.
— AngularJS ng-checked Directive API Reference

If you are using item.checked just to ensure which check box is checked then you can do something like this :
$scope.onbCase = [
{ number:1, selected:false },
{ number:2, selected:false },
{ number:3, selected:false }
];
Here is your functions :
$scope.onbNum = [];
$scope.checkAll = function(){
$scope.onbNum = [];
for(var i=0; i<$scope.onbCase.length;i++){
$scope.onbCase[i].selected = $scope.selectAll;
}
if($scope.selectAll === true){
for(var i=0; i<$scope.onbCase.length;i++){
$scope.onbNum.push($scope.onbCase[i].number);
}
}
}
$scope.checkboxFunc = function(item){
if(item.selected) {
if($scope.onbNum.indexOf(item.number)===-1){
$scope.onbNum.push(
item.number
)
}
}
else {
var pos = $scope.onbNum.indexOf(item.number);
if(pos>-1){
$scope.onbNum.splice(pos,1);
}
$scope.selectAll = false;
}
}
Here is your HTML Page :
<th>
<input type="checkbox" id="selectAll" ng-model="selectAll"
ng-click="checkAll()"/>
</th>
<th> ${Case Number}
</th>
<tr ng-repeat="item in onbCase">
<td><input type="checkbox" name="checkbox"
ng-click="checkboxFunc(item)" ng-model="item.selected"
ng-checked="selectAll || item.selected"/>
</td>
<td>{{item.number}}</td>
</tr>
Hope this will work or give you a idea for what you want.

I'm not sure to exactly know your question , but I hope my answer help you:
add ng-click to your selectAll input like below:
<input type="checkbox" id="selectAll" ng-model="selectAll" ng-change="checkAll()" />
and also add below function to you controller:
$scope.checkAll = function () {
if ($scope.selectAll == true) {
angular.forEach($scope.c.onbCase, function(item) {
if ($scope.onbNum.indexOf(item.number) == -1) {
$scope.onbNum.push(
item.number
);
}
});
} else {
angular.forEach($scope.c.onbCase, function (item) {
if ($scope.onbNum.indexOf(item.number) !== -1) {
var pos = $scope.onbNum.indexOf(item.number);
$scope.onbNum.splice(pos, 1);
}
});
}
}

Related

My drop down list not selected dynamically

I have to select drop down list value dynamically for update functionality in my web site. I also go through similar tutorials and stack overflow question-answer.
I work with angularjs v1.4.2, up till now I tried below code.
HTML:
<label for="ddlDesignationDepartment"> Department</label>
<select name="ddlDesignationDepartment" ng-model="designation.DepartmentId"
ng-options="dept.DepartmentId as dept.DepartmentName for dept in departmentList track by dept.DepartmentId" >
</select>
<br/>
<label for="txtDesignationName"> Designation</label>
<input type="text" name="txtDesignationName"
ng-model="designation.DesignationName"
placeholder="Designation name"/>
<br/>
<label for="txtDescription"> Description</label>
<input type="text" name="txtDescription"
ng-model="designation.Description"
placeholder="Desription"/>
<input type="button" value="{{designation.DesignationId>0?'Update':'Insert'}}"
ng-click="ManageDesignation(designation)" />
<table name="tblDesignationResult">
<tbody ng-if="designationList.length>0">
<tr ng-repeat="des in designationList">
<td>
{{$index+1}}
</td>
<td >
{{des.DesignationName}}
</td>
<td>
{{des.Description}}
</td>
<td >
{{des.DepartmentName}}
</td>
<td>
<input type="button" value="Edit" ng-click="EditDesgnation(des)" />
</td>
</tr>
</tbody>
</table>
AngularJs code:
(function () {
'use strict';
///Decalre angular controllar for Designation
angular.module('AngularDemo').controller('DesignationCtrl', ['$scope', '$rootScope', 'DesignationService', 'DepartmentService', DesignationCtrl]);
///Designation controllar
function DesignationCtrl($scope, $rootScope, DesignationService,
DepartmentService) {
///Get or set all Designation
$scope.designationList = [];
///Get or set all Department
$scope.departmentList = [];
///Get or set Designation
$scope.designation = new Designation();
///Retrive all Designation by DesignationService
$scope.GetAllDesignations = function () {
DesignationService.GetAllDesignations().then(function (response) {
if (response && response.data) {
/// Success block
if (response.data.Result) {
$scope.designationList = angular.copy(response.data.Result);
}
else {
alert(response.data.Message);
}
}
});
}
/// Manage Insert / Update / Delete on specific Designation by
///DesignationService
$scope.ManageDesignation = function ( des) {
DesignationService.ManageDesignation(des).then(function (response) {
if (response && response.data) {
/// Success block
if (response.data.Result) {
$scope.departmentList = angular.copy(response.data.Result);
}
else {
alert(response.data.Message);
}
}
});
$scope.Init();
}
///Retrive all Department by DepartmentService
$scope.GetAllDepartments = function () {
DepartmentService.GetAllDepartments().then(function (response) {
if (response && response.data) {
/// Success block
if (response.data.Result) {
$scope.departmentList = angular.copy(response.data.Result);
}
else {
alert(response.data.Message);
}
}
});
}
///Edit Designation
$scope.EditDesgnation = function (des) {
$scope.designation = des;
}
///Inilise Designation controllar
$scope.Init = function () {
$scope.designation = new Designation();
$scope.GetAllDesignations();
$scope.GetAllDepartments();
}
}
})();
///JavaScript Class of Designation
function Designation() {
this.DesignationId = 0;
this.DesignationName='';
this.Description = '';
this.DepartmentId = 0;
}
Designation.prototype = {
constructor: Designation
}
Sample Database
Department{DepartmentId int, DepartmentName varchar(max)}
Designation{DesignationId int,DesignationName varchar(max),Description varchar(max),DepartmentId int}
All services working fine, initially everything is fine all data are display in Result table, Dropdown list was also show all departments. But the problem is when I click on edit for update any record textbox value are filled for specific data but the Department Dropdown list value are not select.
Be careful when using select as and track by in the same expression.
Given this array of items on the $scope:
$scope.items = [{
id: 1,
label: 'aLabel',
subItem: { name: 'aSubItem' }
}, {
id: 2,
label: 'bLabel',
subItem: { name: 'bSubItem' }
}];
This will work:
<select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>
$scope.selected = $scope.items[0];
but this will not work:
<select ng-options="item.subItem as item.label for item in items track by item.id" ng-model="selected"></select>
$scope.selected = $scope.items[0].subItem;
In both examples, the track by expression is applied successfully to each item in the items array. Because the selected option has been set programmatically in the controller, the track by expression is also applied to the ngModel value. In the first example, the ngModel value is items[0] and the track by expression evaluates to items[0].id with no issue. In the second example, the ngModel value is items[0].subItem and the track by expression evaluates to items[0].subItem.id (which is undefined). As a result, the model value is not matched against any and the appears as having no selected value
so in your case as well change this
ng-options="dept.DepartmentId as dept.DepartmentName for dept in departmentList track by dept.DepartmentId
to
ng-options="dept as dept.DepartmentName for dept in departmentList track by dept.DepartmentId
since dept[0].DepartmentId.id do not exists

Enable/Disable button in AngularJS

I have a table that has a checkbox. It has a select ALL javascript function and a select one by one function. My html file looks like this for the delete button:
<button data-toggle="modal" data-target="#rejectModal" contenteditable="false" id="delbutton" ng-model="delbutton" ng-disabled="countChecked() == 0">Delete</span></button>
Select All Checkbox:
<th class="">
<input type="checkbox" name="select" id="checkAll" ng-model="selectAllRawSCP"/>
</th>
table details:
<tr ng-repeat=" item in rawSCAP | orderBy:sort">
<td>
<input type="checkbox" name="select" value="checked" ng-model="item.checked"/>
</td>
I used the code I saw in one of the answers here in stack overflow to disable the delete button if there is no checkbox checked. It looks like this:
$scope.countChecked = function(){
var count = 0;
angular.forEach($scope.rawSCAP, function(value){
if (value.checked) count++;
});
return count;
}
But using this, my page returns an error which isTypeError: Cannot read property 'checked' of null
And also I need to enable delete button even if I used select all
The error is pretty clear, it cannot access the property checked of the rawSCAP itens. You have to guarantee rawSCAP itens checked property is not null before you try to use it in ng-model.
You could try to initialize it before with some value you want. Check this on how to do it.
There are some conditions you need to follow to use the <<ng-model>>.checked, which is a plain array can't be used for checkbox, it must be an array of objects. Also please change your function to below.
$scope.countChecked = function() {
var count = 0;
angular.forEach($scope.rawSCAP, function(value) {
value.checked = value.checked || 0;
if (value.checked) count++;
});
return count;
}
The main line which does the work is value.checked = value.checked || 0; Here if the value.checked is undefined, then the 0 will get assigned to value.checked, hence you won't get the error!
var app = angular.module('myApp', []);
app.controller('MyController', function MyController($scope) {
$scope.rawSCAP = [{
item: 1
}, {
item: 2
}, {
item: 3
}, {
item: 4
}, {
item: 5
}, {
item: 6
}, {
item: 7
}];
$scope.countChecked = function() {
var count = 0;
angular.forEach($scope.rawSCAP, function(value) {
value.checked = value.checked || 0;
if (value.checked) count++;
});
return count;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller='MyController' ng-app="myApp">
<button data-toggle="modal" data-target="#rejectModal" contenteditable="false" id="delbutton" ng-model="delbutton" ng-disabled="countChecked() == 0">Delete</button>
<table>
<th class="">
<input type="checkbox" name="select" id="checkAll" ng-model="selectAllRawSCP" />
</th>
<tr ng-repeat=" item in rawSCAP | orderBy:sort">
<td>
<input type="checkbox" name="select" value="checked" ng-model="item.checked" />{{item.item}}
</td>
</tr>
</table>
</div>

Remove selected rows on a button click in angular js

I have a table with check box for each row .
I need to remove the rows for the selected check boxes in the table on a button click. (this button is outside ng-repeat).
The index of the selected rows are populated to an array using ng-change function but i'm unable to remove the selected rows on a single button click
Here is the Fiddle
HTML
<div ng-app="approvalApp">
<div ng-controller="SimpleApprovalController" >
<table style="width:90%" border="5" >
<tr>
<th><input type="checkbox" ng-model="CheckAllData" ng- change="selectAll()" /></th>
<th>Date</th>
<th>AssociateID</th>
<th>Check-In</th>
<th>Checkout</th>
</tr>
<tr data-ng-repeat="approval in approvalitems">
<td><input type="checkbox" value="{{approval.ReqId}}" data-ng-model="approval.selected" data-ng-change="SelectDeselect($index)"/></td>
<td>{{approval.Date}}</td>
<td>{{approval.AssociateID}}</td>
<td>{{approval.CheckIn}}</td>
<td>{{approval.Checkout}}</td>
</tr>
</table>
<input type="button" value="Approve" data-ng-model="ApproveIndex" data-ng-click="ApproveRequest()" />
Script
$scope.SelectDeselect=function(index)
{
$scope.getIndexvalues = [];
angular.forEach($scope.approvalitems, function (approval,index) {
if (!!approval.selected) {
$scope.getIndexvalues.push(index);
$scope.CheckAllData = false;
}
});
console.log($scope.getIndexvalues);
};
$scope.ApproveRequest = function () {
$scope.selectedIdsArray = [{}];
angular.forEach($scope.approvalitems, function (item) {
if (!!item.selected) {
$scope.selectedIdsArray.push({ Reqid: item.ReqId, Status: "Approved" });
$scope.CheckAllData = false;
}
});
};
};
So how to use getIndexvalues in approverequest function , or is there any better way to remove it using other angular directive.
I'm a newbie to angular js .
Fiddle: http://jsfiddle.net/jpk547zp/1/
$scope.ApproveRequest = function () {
$scope.selectedIdsArray = [{}];
$scope.approvalitemsNew = [];
angular.forEach($scope.approvalitems, function (item) {
if (!!item.selected) {
$scope.selectedIdsArray.push({ Reqid: item.Date, Status: "Approved" });
$scope.CheckAllData = false;
item.hideThis = true;
console.log($scope.selectedIdsArray);
} else {
$scope.approvalitemsNew.push(item);
}
});
$scope.approvalitems = $scope.approvalitemsNew;
$scope.getIndexvalues = [];
};
Hope this helps.
you can simply do
$scope.ApproveRequest = function () {
$scope.approvalitems = $scope.approvalitems.filter(function(i){
return !i.selected;
});
};

when check a checkbox, unchecked other with javascript

I fill the table with a ADODB.Recordset. I have 25 rows. But it can change. And last column is checkboxes.
Only one checkbox can select. Check one and uncheck others automatic.
<input class="cb" id="txtdurum_<%=counter%>" name="txtdurum" type="checkbox" />
Help please :)
Try this code. Add an onchange event to each input checkbox.
<input class="cb" id="txtdurum_<%=counter%>" name="txtdurum" type="checkbox" onchange="check(this)"/>
JS:
function check(element){
if(element.checked){
var checkboxes = document.getElementsByClassName('cb');
for(var i=0;i<checkboxes.length;i++){
if(checkboxes[i]!=element)
checkboxes[i].checked = false;
}
}
}
Example Fiddle.
You can use jQuery:
$('.cb').change(function(){
$('.cb').prop('checked',false);
$(this).prop('checked',true);
});
This adds a change-listener to all checkboxes with the "cb" class-Attribute.
Place that code-fragment into the jquery-ready-function.
Example: JSFiddle
UPDATE1:
If you also want to enable, that the user can uncheck all:
$('.cb').change(function(){
var checkState = $(this).prop('checked');
$('.cb').prop('checked',false);
$(this).prop('checked', checkState);
});
Example: JSFiddle2
But:
better use radiobuttons
While I would – strongly – recommend that you use <input> elements of type="radio" (with a 'choose nothing' option, if that's required), I was intrigued enough to spend the last few hours putting together this approach.
This is one way of doing it, it feels little over-the-top and it's not quite as streamlined as I'd like, but it does suffice to meet your requirements. I've provided a simple demo for the introduction, and the JavaScript is commented throughout:
var Limit = (function () {
// private to this function, but shared by all instances:
// simple 'closest' function;
// start: DOM Node,
// needle: String, the tagName of the ancestor to find.
// if no ancestor exists (we stop at the <body> element)
// function returns null:
var closest = function (start, needle) {
// we begin at the 'start' node, but use
// the 'current' variable as a pointer as
// we move through the ancestors:
var current = start,
// converting the tagName to lower-case,
// for predictable comparisons:
find = needle.toLowerCase();
// while the tagName of the current element-node is not
// what we're looking for AND the current element-node is
// not the <body> element:
while (current.tagName.toLowerCase() !== find && current.tagName.toLowerCase() !== 'body') {
// we set the current node to its parentNode,
// thereby ascending through the DOM:
current = current.parentNode;
}
// if the tagName of the current element-node is 'body'
// we return null, otherwise we return that current node:
return current.tagName.toLowerCase() === 'body' ? null : current;
};
return function (groupSelector) {
// protected variables, available on a
// per-instance basis:
// the array in which we'll hold the selected
// <input> elements as they're checked:
var checked = [],
// the group of elements to which this instance
// will apply:
group = document.querySelectorAll(groupSelector),
// the defaults:
// allowInvalidity, Boolean:
// true: allows the user to select more than
// the maximum number of choices.
// false: prevents the selection of options
// beyond the maxumum number.
// fifo, Boolean:
// true: should the user try to select more
// than the maximum number of choices
// the first element in the array is
// removed.
// false: should the user try to select more
// than the maximum number of choices
// subsequent choices are prevented.
// maxChoices, Number:
// defines the maximum number of choices
// that can be made.
// parentErrorClass, String:
// the class-name to be applied to the
// parent of the <input> elements when
// the user chooses more than the maximum
// number of options (requires
// settings.invalidity to be true).
defaults = {
'allowInvalidity': false,
'fifo': true,
'maxChoices': 1,
'parentErrorClass': 'error'
};
// the object containing the function(s) we
// make available:
return {
// opts is the user-defined settings
// passed in:
'nOnly': function (opts) {
// a simple, though potentially costly,
// means of avoiding JavaScript's
// pass-by-reference (which prevents
// settings = dafaults from working),
// here creating a copy via the JSON functions:
var settings = JSON.parse(JSON.stringify(defaults));
// iterating over the user-defined settings in the
// supplied opts object:
for (var setting in opts) {
// avoiding iterating over inherited properties
// from the Object.prototype:
if (opts.hasOwnProperty(setting)) {
// setting the settings options to
// those supplied in the opts object:
settings[setting] = opts[setting];
}
}
// iterating over the Array-like NodeList returned by
// document.querySelectorAll() (when we retrieved the
// nodes for this 'group'), using Function.prototype.call()
// to apply Array.prototype.forEach():
Array.prototype.forEach.call(group, function (input) {
// there are three arguments available to
// Array.prototype.forEach(), the names are
// user-defined (within variable-naming constraints);
// the first (here: 'input') the current array-element
// from the array over which we're iterating,
// the second (not used) is the index of that array-element,
// the third (not used) is the full array over which
// we iterate.
// here we bind the anonymous function as the 'change'
// event-handler on each of the <input> elements in
// the parent group:
input.addEventListener('change', function (event) {
if (input.checked && settings.allowInvalidity === false) {
// add the <input> to the checked array:
checked.push(input);
// if too many choices have been made:
if (checked.length > settings.maxChoices) {
// we call Array.prototype.pop() (if
// settings.fifo is true) or
// Array.prototype.shift() (if
// settings.fifo is not exactly-true)
// to select the first element of the
// checked Array (shift()) or the last
// element (pop()) and set that element's
// checked property to false. Using shift()
// or pop() also removes it from the array:
checked[settings.fifo === true ? 'shift' : 'pop']().checked = false;
}
} else if (input.checked && settings.allowInvalidity === true) {
// we simply add the <input> to the array:
checked.push(input)
} else {
// we test that the <input> element is in
// the checked Array:
if (checked.indexOf(input) > -1) {
// using Array.prototype.splice() to
// remove it from the Array; using
// Array.prototype.indexOf() (again)
// to retrieve its index in the Array:
checked.splice(checked.indexOf(input), 1);
}
}
// iterating over the group, with Array.prototype.forEach():
Array.prototype.forEach.call(group, function (input) {
// if the <input> is not checked, or the number of choices
// is less than the permitted maximum:
if (!input.checked || checked.length <= settings.maxChoices) {
// we remove the parentErrorClass from the parentNode:
input.parentNode.classList.remove(settings.parentErrorClass);
// otherwise if the <input> is checked, AND
// there are too many choices:
} else if (input.checked && checked.length > settings.maxChoices) {
// we add the parentErrorClass to the parentNode:
input.parentNode.classList.add(settings.parentErrorClass);
}
});
});
});
}
};
};
})();
new Limit('.group1 input').nOnly({
'allowInvalidity': true,
'maxChoices': 3
});
new Limit('.group2 input').nOnly({
'maxChoices': 1,
'fifo': false
});
new Limit('.group3 input').nOnly({
'allowInvalidity': true,
'maxChoices' : 2,
'parentErrorClass' : 'oops'
});
var Limit = (function() {
var closest = function(start, needle) {
var current = start,
find = needle.toLowerCase();
while (current.tagName.toLowerCase() !== find && current.tagName.toLowerCase() !== 'body') {
current = current.parentNode;
}
return current.tagName.toLowerCase() === 'body' ? null : current;
};
return function(groupSelector) {
var checked = [],
group = document.querySelectorAll(groupSelector),
defaults = {
'allowInvalidity': false,
'fifo': true,
'maxChoices': 1,
'parentErrorClass': 'error'
};
return {
'nOnly': function(opts) {
var settings = JSON.parse(JSON.stringify(defaults));
for (var setting in opts) {
if (opts.hasOwnProperty(setting)) {
settings[setting] = opts[setting];
}
}
Array.prototype.forEach.call(group, function(input) {
input.addEventListener('change', function(event) {
if (input.checked && settings.allowInvalidity === false) {
checked.push(input);
if (checked.length > settings.maxChoices) {
checked[settings.fifo === true ? 'shift' : 'pop']().checked = false;
}
} else if (input.checked && settings.allowInvalidity === true) {
checked.push(input)
} else {
if (checked.indexOf(input) > -1) {
checked.splice(checked.indexOf(input), 1);
}
}
Array.prototype.forEach.call(group, function(input) {
if (!input.checked || checked.length <= settings.maxChoices) {
input.parentNode.classList.remove(settings.parentErrorClass);
} else if (input.checked && checked.length > settings.maxChoices) {
input.parentNode.classList.add(settings.parentErrorClass);
}
});
});
});
}
};
};
})();
new Limit('.group1 input').nOnly({
'allowInvalidity': true,
'maxChoices': 3
});
new Limit('.group2 input').nOnly({
'maxChoices': 1,
'fifo': false
});
new Limit('.group3 input').nOnly({
'allowInvalidity': true,
'maxChoices': 2,
'parentErrorClass': 'oops'
});
form {
-moz-column-count: 3;
-webkit-column-count: 3;
column-count: 3;
-moz-break-inside: avoid-column;
-webkit-break-inside: avoid-column;
break-inside: avoid-column;
}
label {
display: block;
border: 2px solid transparent;
transition: all 0.5s linear;
}
.error {
border: 2px solid #f00;
}
.oops {
background-color: #f90;
}
<form action="#" method="post">
<fieldset>
<legend>Group 1</legend>
<label class="group1">input 1
<input type="checkbox" />
</label>
<label class="group1">input 2
<input type="checkbox" />
</label>
<label class="group1">input 3
<input type="checkbox" />
</label>
<label class="group1">input 4
<input type="checkbox" />
</label>
<label class="group1">input 5
<input type="checkbox" />
</label>
</fieldset>
<fieldset>
<legend>Group 2</legend>
<label class="group2">input 1
<input type="checkbox" />
</label>
<label class="group2">input 2
<input type="checkbox" />
</label>
<label class="group2">input 3
<input type="checkbox" />
</label>
<label class="group2">input 4
<input type="checkbox" />
</label>
<label class="group2">input 5
<input type="checkbox" />
</label>
</fieldset>
<fieldset>
<legend>Group 3</legend>
<label class="group3">input 1
<input type="checkbox" />
</label>
<label class="group3">input 2
<input type="checkbox" />
</label>
<label class="group3">input 3
<input type="checkbox" />
</label>
<label class="group3">input 4
<input type="checkbox" />
</label>
<label class="group3">input 5
<input type="checkbox" />
</label>
</fieldset>
</form>
External JS Fiddle demo, for experimentation.
To apply this to your own situation, the function can be called like so:
// here, the only difference is the CSS selector
// passed to the Constructor:
new Limit('table input[type=checkbox]').nOnly({
'maxChoices': 1
});
var Limit = (function() {
var closest = function(start, needle) {
var current = start,
find = needle.toLowerCase();
while (current.tagName.toLowerCase() !== find && current.tagName.toLowerCase() !== 'body') {
current = current.parentNode;
}
return current.tagName.toLowerCase() === 'body' ? null : current;
};
return function(groupSelector) {
var checked = [],
group = document.querySelectorAll(groupSelector),
defaults = {
'allowInvalidity': false,
'fifo': true,
'maxChoices': 1,
'parentErrorClass': 'error'
};
return {
'nOnly': function(opts) {
var settings = JSON.parse(JSON.stringify(defaults));
for (var setting in opts) {
if (opts.hasOwnProperty(setting)) {
settings[setting] = opts[setting];
}
}
Array.prototype.forEach.call(group, function(input) {
input.addEventListener('change', function(event) {
if (input.checked && settings.allowInvalidity === false) {
checked.push(input);
if (checked.length > settings.maxChoices) {
checked[settings.fifo === true ? 'shift' : 'pop']().checked = false;
}
} else if (input.checked && settings.allowInvalidity === true) {
checked.push(input)
} else {
if (checked.indexOf(input) > -1) {
checked.splice(checked.indexOf(input), 1);
}
}
Array.prototype.forEach.call(group, function(input) {
if (!input.checked || checked.length <= settings.maxChoices) {
input.parentNode.classList.remove(settings.parentErrorClass);
} else if (input.checked && checked.length > settings.maxChoices) {
input.parentNode.classList.add(settings.parentErrorClass);
}
});
});
});
}
};
};
})();
new Limit('table input[type=checkbox]').nOnly({
'maxChoices': 1
});
<table>
<tr>
<td>row 1</td>
<td>
<input type="checkbox" />
</td>
</tr>
<tr>
<td>row 2</td>
<td>
<input type="checkbox" />
</td>
</tr>
<tr>
<td>row 3</td>
<td>
<input type="checkbox" />
</td>
</tr>
<tr>
<td>row 4</td>
<td>
<input type="checkbox" />
</td>
</tr>
<tr>
<td>row 5</td>
<td>
<input type="checkbox" />
</td>
</tr>
<tr>
<td>row 6</td>
<td>
<input type="checkbox" />
</td>
</tr>
<tr>
<td>row 7</td>
<td>
<input type="checkbox" />
</td>
</tr>
<tr>
<td>row 8</td>
<td>
<input type="checkbox" />
</td>
</tr>
<tr>
<td>row 9</td>
<td>
<input type="checkbox" />
</td>
</tr>
<tr>
<td>row 10</td>
<td>
<input type="checkbox" />
</td>
</tr>
</table>
External JS Fiddle demo, for experimentation.
This is, obviously, a representative demonstration since you neglected to provide the relevant (mcve) HTML, however since it relies only on an appropriate selector it should be easily applicable to your situation.
References:
CSS:
Attribute-selectors ([attribute=value]).
column-count.
CSS transitions.
JavaScript:
Array.prototype.forEach().
Array.prototype.indexOf().
Array.prototype.push().
Array.prototype.shift().
Array.prototype.splice().
Conditional/ternary Operator (assesment ? ifTrue : ifFalse).
document.querySelector().
document.querySelectorAll().
Element.classList API.
EventTarget.addEventListener().
for...in loop.
Function.prototype.call().
JSON.parse().
JSON.stringify().
Node.parentNode.
Node.tagName.
Object.prototype.hasOwnProperty().
String.prototype.toLowerCase().

knockoutjs deselect/select all checkboxes when one or more items deselected

This is similar to, but different from other questions around this topic.
I have a table with a list of records, each having a select checkbox.
In the table header I have a "Select All" checkbox.
When the user checks/unchecks "Select All" the records are selected/unselected. This works fine.
However, I need to deselect my "Select All" checkbox when one or more of the records are deselected.
My markup:
<table>
<thead>
<tr>
<th>Name</th>
<th><input type="checkbox" data-bind="checked: SelectAll" /></th>
</tr>
</thead>
<tbody data-bind="foreach: $data.People">
<tr>
<td data-bind="text: Name"></td>
<td class="center"><input type="checkbox" data-bind="checked: Selected" /></td>
</tr>
</tbody>
</table>
My script (edited):
function MasterViewModel() {
var self = this;
self.People = ko.observableArray();
self.SelectAll = ko.observable(false);
self.SelectAll.subscribe(function (newValue) {
ko.utils.arrayForEach(self.People(), function (person) {
person.Selected(newValue);
});
});
}
my.Person = function (name, selected) {
var self = this;
self.Name = name;
self.Selected = ko.observable(false);
}
This works
http://jsfiddle.net/AneL9/
self.SelectAll = ko.computed({
read: function() {
var item = ko.utils.arrayFirst(self.People(), function(item) {
return !item.Selected();
});
return item == null;
},
write: function(value) {
ko.utils.arrayForEach(self.People(), function (person) {
person.Selected(value);
});
}
});
but will give you a ordo n ^ 2 problem when selecting deselecting all, you can use a pasuable computed to get around that
http://www.knockmeout.net/2011/04/pausing-notifications-in-knockoutjs.html
edit: You can also extend the computed with a throttle, this way you avoid the ordo n^2 problem
.extend({ throttle: 1 })
http://jsfiddle.net/AneL9/44/
You should make SelectAll computed observable like this:
self.SelectAll = ko.computed({
read: function() {
var persons = self.People();
for (var i = 0, l = persons.length; i < l; i++)
if (!persons[i].Selected()) return false;
return true;
},
write: function(value) {
ko.utils.arrayForEach(self.People(), function(person){
person.Selected(value);
});
}
});
and strip SelectAll.subscribe out.
http://jsfiddle.net/Yqj59/

Categories