I have a few checkboxes:
In the HTML (supposing that the checkboxes are in the first column of every row in a table).
<tr ng-repeat="item in fruits">
<td><input type="checkbox" ng-model="item.checked" ng-click="getChecked(item)"></td>
<td ng-bind="fruit.name"></td>
<td ng-bind="fruit.color"></td>
...
</tr>
In the controllers.js
file:
// The data initialization part...
$scope.fruits = [
{
name: ....,
color:....
},
{
name: ....,
color:....
}
...
];
// The checked or not data is stored in the object array elements themselves
$scope.fruits.forEach(function(item){
item.checked = false;
});
// The array to store checked fruit items
$scope.checkedItems = [];
// Every click on any checkbox will trigger the filter to find checked items
$scope.getChecked = function(item){
$scope.checkedItems = $filter("filter")($scope.fruits,{checked:true});
};
I think the easiest workaround would be to use 'select' with 'multiple' specified:
<select ng-model="selectedfruit" multiple ng-options="v for v in fruit"></select>
Otherwise, I think you'll have to process the list to construct the list
(by $watch()
ing the model array bind with checkboxes).
Based on my other post here, I have made a reusable directive.
Check out the GitHub repository
(function () {
angular
.module("checkbox-select", [])
.directive("checkboxModel", ["$compile", function ($compile) {
return {
restrict: "A",
link: function (scope, ele, attrs) {
// Defining updateSelection function on the parent scope
if (!scope.$parent.updateSelections) {
// Using splice and push methods to make use of
// the same "selections" object passed by reference to the
// addOrRemove function as using "selections = []"
// creates a new object within the scope of the
// function which doesn't help in two way binding.
scope.$parent.updateSelections = function (selectedItems, item, isMultiple) {
var itemIndex = selectedItems.indexOf(item)
var isPresent = (itemIndex > -1)
if (isMultiple) {
if (isPresent) {
selectedItems.splice(itemIndex, 1)
} else {
selectedItems.push(item)
}
} else {
if (isPresent) {
selectedItems.splice(0, 1)
} else {
selectedItems.splice(0, 1, item)
}
}
}
}
// Adding or removing attributes
ele.attr("ng-checked", attrs.checkboxModel + ".indexOf(" + attrs.checkboxValue + ") > -1")
var multiple = attrs.multiple ? "true" : "false"
ele.attr("ng-click", "updateSelections(" + [attrs.checkboxModel, attrs.checkboxValue, multiple].join(",") + ")")
// Removing the checkbox-model attribute,
// it will avoid recompiling the element infinitly
ele.removeAttr("checkbox-model")
ele.removeAttr("checkbox-value")
ele.removeAttr("multiple")
$compile(ele)(scope)
}
}
}])
// Defining app and controller
angular
.module("APP", ["checkbox-select"])
.controller("demoCtrl", ["$scope", function ($scope) {
var dc = this
dc.list = [
"selection1",
"selection2",
"selection3"
]
// Define the selections containers here
dc.multipleSelections = []
dc.individualSelections = []
}])
})()
label {
display: block;
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css" />
</head>
<body ng-app="APP" ng-controller="demoCtrl as dc">
<h1>checkbox-select demo</h1>
<h4>Multiple Selections</h4>
<label ng-repeat="thing in dc.list">
<input type="checkbox" checkbox-model="dc.multipleSelections" checkbox-value="thing" multiple>
{{thing}}
</label>
<p>dc.multipleSelecitons:- {{dc.multipleSelections}}</p>
<h4>Individual Selections</h4>
<label ng-repeat="thing in dc.list">
<input type="checkbox" checkbox-model="dc.individualSelections" checkbox-value="thing">
{{thing}}
</label>
<p>dc.individualSelecitons:- {{dc.individualSelections}}</p>
<script data-require="jquery@3.0.0" data-semver="3.0.0" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.js"></script>
<script data-require="angular.js@1.5.6" data-semver="1.5.6" src="https://code.angularjs.org/1.5.6/angular.min.js"></script>
<script src="script.js"></script>
</body>
</html>
Since you accepted an answer in which a list was not used, I'll assume the answer to my comment question is "No, it doesn't have to be a list". I also had the impression that maybe you were rending the HTML server side, since "checked" is present in your sample HTML (this would not be needed if ng-model were used to model your checkboxes).
Anyway, here's what I had in mind when I asked the question, also assuming you were generating the HTML server-side:
<div ng-controller="MyCtrl"
ng-init="checkboxes = {apple: true, orange: false, pear: true, naartjie: false}">
<input type="checkbox" ng-model="checkboxes.apple">apple
<input type="checkbox" ng-model="checkboxes.orange">orange
<input type="checkbox" ng-model="checkboxes.pear">pear
<input type="checkbox" ng-model="checkboxes.naartjie">naartjie
<br>{{checkboxes}}
</div>
ng-init allows server-side generated HTML to initially set certain checkboxes.
Fiddle.
There is a way to work on the array directly and use ng-model at the same time through ng-model-options="{ getterSetter: true }"
.
The trick is to use a getter/setter function in your ng-model. This way you can use an array as your real model and "fake" the booleans in the input's model:
<label ng-repeat="fruitName in ['apple', 'orange', 'pear', 'naartjie']">
<input
type="checkbox"
ng-model="fruitsGetterSetterGenerator(fruitName)"
ng-model-options="{ getterSetter: true }"
> {{fruitName}}
</label>
$scope.fruits = ['apple', 'pear']; // pre checked
$scope.fruitsGetterSetterGenerator = function(fruitName){
return function myGetterSetter(nowHasFruit){
if (nowHasFruit !== undefined){
// Setter
fruitIndex = $scope.fruits.indexOf(fruit);
didHaveFruit = (fruitIndex !== -1);
mustAdd = (!didHaveFruit && nowHasFruit);
mustDel = (didHaveFruit && !nowHasFruit);
if (mustAdd){
$scope.fruits.push(fruit);
}
if (mustDel){
$scope.fruits.splice(fruitIndex, 1);
}
}
else {
// Getter
return $scope.user.fruits.indexOf(fruit) !== -1;
}
}
}
CAVEAT You shouldn't use this method if your arrays are big as myGetterSetter
will be called a lot of times.
For more on that, see https://docs.angularjs.org/api/ng/directive/ngModelOptions.