<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset=utf-8>
<!--
Created using JS Bin
http://jsbin.com
Copyright (c) 2021 by anonymous (http://jsbin.com/ImAqUC/1/edit)
Released under the MIT license: http://jsbin.mit-license.org
-->
<meta name="robots" content="noindex">
<title>How can AngularJS bind to list of checkbox values?</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.min.js"></script>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<div class="page-header">
<h1><a href="http://stackoverflow.com/q/14514461/697154">How can AngularJS bind to list of checkbox values?</a></h1>
</div>
<div ng-controller="SimpleArrayCtrl">
<h3>With a simple array as input data</h3>
<dl>
<dt>Pros</dt>
<dd>simple data structure and toggling by name is easy to handle</dd>
<dt>Cons</dt>
<dd>add/remove is cumbersome as two lists (the input and selection) have to be managed</dd>
</dl>
<div class="row">
<div class="col-md-6">
<h4>selectables</h4>
<div class="form-group">
<label ng-repeat="fruitName in fruits" class="checkbox-inline">
<input type="checkbox" name="selectedFruits[]" value="{{fruitName}}" ng-checked="selection.indexOf(fruitName) > -1" ng-click="toggleSelection(fruitName)"> {{fruitName}}
</label>
</div>
</div>
<div class="col-md-6">
<p><strong>Toggling</strong> by name is easy in this case, because the needed helper method can be reused.</p>
<button class="btn btn-default" ng-click="toggleSelection('naartjie')">Toggle <em>naartjie</em></button>
</div>
</div>
<div class="row">
<div class="col-md-6">
<h4>selection</h4>
<pre>{{selection|json}}</pre>
</div>
<div class="col-md-6">
<h4>input</h4>
<pre>{{fruits|json}}</pre>
</div>
</div>
</div>
<hr>
<div ng-controller="ObjectArrayCtrl">
<h3>With an object array as input data</h3>
<dl>
<dt>Pros</dt>
<dd>add/remove is very easy</dd>
<dt>Cons</dt>
<dd>somewhat more complex data structure and toggling by name is cumbersome or requires a helper method</dd>
</dl>
<div class="row">
<div class="col-md-6">
<h4>selectables</h4>
<div class="form-group">
<label ng-repeat="fruit in fruits" class="checkbox-inline">
<!--
- use `value="{{fruit.name}}"` to give the input a real value, in case the form gets submitted
traditionally
- use `ng-checked="fruit.selected"` to have the checkbox checked based on some angular expression
(no two-way-data-binding)
- use `ng-model="fruit.selected"` to utilize two-way-data-binding. Note that `.selected`
is arbitrary. The property name could be anything and will be created on the object if not present.
-->
<input type="checkbox" name="selectedFruits[]" value="{{fruitName}}" ng-model="fruit.selected"> {{fruit.name}}
</label>
</div>
</div>
<div class="col-md-6">
<p><strong>Toggling</strong> by name is not so easy in this case, because the the code is either rather ugly, or a helper method is needed.</p>
<button class="btn btn-default" ng-click="(fruits|filter:{name:'naartjie'})[0].selected = !(fruits|filter:{name:'naartjie'})[0].selected">Toggle <em>naartjie</em></button>
</div>
</div>
<div class="row">
<div class="col-md-6">
<h4>selection as simple array using $watch</h4>
<pre>{{selection|json}}</pre>
<h4>selection as simple array using a custom filter</h4>
<pre>{{fruits|fruitSelection:'name'|json}}</pre>
<h4>selection using the default filter</h4>
<pre>{{fruits|filter:{selected:true}|json}}</pre>
<h4>selection using a helper function</h4>
<pre>{{selectedFruits()|json}}</pre>
</div>
<div class="col-md-6">
<h4>input</h4>
<pre>{{fruits|json}}</pre>
</div>
</div>
</div>
</div>
<script>
(function (app) {
'use strict';
app.controller('SimpleArrayCtrl', ['$scope', function SimpleArrayCtrl($scope) {
// fruits
$scope.fruits = ['apple', 'orange', 'pear', 'naartjie'];
// selected fruits
$scope.selection = ['apple', 'pear'];
// toggle selection for a given fruit by name
$scope.toggleSelection = function toggleSelection(fruitName) {
var idx = $scope.selection.indexOf(fruitName);
// is currently selected
if (idx > -1) {
$scope.selection.splice(idx, 1);
}
// is newly selected
else {
$scope.selection.push(fruitName);
}
};
}]);
app.controller('ObjectArrayCtrl', ['$scope', 'filterFilter', function ObjectArrayCtrl($scope, filterFilter) {
// fruits
$scope.fruits = [
{ name: 'apple', selected: true },
{ name: 'orange', selected: false },
{ name: 'pear', selected: true },
{ name: 'naartjie', selected: false }
];
// selected fruits
$scope.selection = [];
// helper method
$scope.selectedFruits = function selectedFruits() {
return filterFilter($scope.fruits, { selected: true });
};
// watch fruits for changes
$scope.$watch('fruits|filter:{selected:true}', function (nv) {
$scope.selection = nv.map(function (fruit) {
return fruit.name;
});
}, true);
}]);
/**
* custom filter
*/
app.filter('fruitSelection', ['filterFilter', function (filterFilter) {
return function fruitSelection(input, prop) {
return filterFilter(input, { selected: true }).map(function (fruit) {
return fruit[prop];
});
};
}]);
})(angular.module('app', []));
</script>
</body>
</html>