I have a few checkboxes:
<input type='checkbox' value="apple" checked>
<input type='checkbox' value="orange">
<input type='checkbox' value="pear" checked>
<input type='checkbox' value="naartjie">
That I would like to bind to a list in my controller such that whenever a checkbox is changed the controller maintains a list of all the checked values, for example, ['apple', 'pear']
.
ng-model seems to only be able to bind the value of one single checkbox to a variable in the controller.
Is there another way to do it so that I can bind the four checkboxes to a list in the controller?
<input type='checkbox' ng-model="checkboxes.apple">
, etc. Model would be:{"apple":true,"orange":false,"pear":true,"naartjie":true}
naartjie
!? That just gives you away boet! :D
There are two ways to approach this problem. Either use a simple array or an array of objects. Each solution has it pros and cons. Below you'll find one for each case.
With a simple array as input data
The HTML could look like:
<label ng-repeat="fruitName in fruits">
<input
type="checkbox"
name="selectedFruits[]"
value="{{fruitName}}"
ng-checked="selection.indexOf(fruitName) > -1"
ng-click="toggleSelection(fruitName)"
> {{fruitName}}
</label>
And the appropriate controller code would be:
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);
}
};
}]);
Pros: Simple data structure and toggling by name is easy to handle
Cons: Add/remove is cumbersome as two lists (the input and selection) have to be managed
With an object array as input data
The HTML could look like:
<label ng-repeat="fruit in fruits">
<!--
- 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="{{fruit.name}}"
ng-model="fruit.selected"
> {{fruit.name}}
</label>
And the appropriate controller code would be:
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 to get selected fruits
$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);
}]);
Pros: Add/remove is very easy
Cons: Somewhat more complex data structure and toggling by name is cumbersome or requires a helper method
Demo: http://jsbin.com/ImAqUC/1/
A simple solution:
<div ng-controller="MainCtrl">
<label ng-repeat="(color,enabled) in colors">
<input type="checkbox" ng-model="colors[color]" /> {{color}}
</label>
<p>colors: {{colors}}</p>
</div>
<script>
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope){
$scope.colors = {Blue: true, Orange: true};
});
</script>
http://plnkr.co/edit/U4VD61?p=preview
(color,enabled) in colors
do?
colors
is an object, when you iterate it -- you get pairs of (key,value)
.
colors
should be named isSelected
, it is much easier to read isSelected[color]
than colors[color]
<input type='checkbox' ng-repeat="fruit in fruits"
ng-checked="checkedFruits.indexOf(fruit) != -1" ng-click="toggleCheck(fruit)">
.
function SomeCtrl ($scope) {
$scope.fruits = ["apple, orange, pear, naartjie"];
$scope.checkedFruits = [];
$scope.toggleCheck = function (fruit) {
if ($scope.checkedFruits.indexOf(fruit) === -1) {
$scope.checkedFruits.push(fruit);
} else {
$scope.checkedFruits.splice($scope.checkedFruits.indexOf(fruit), 1);
}
};
}
Here's a quick little reusable directive that seems to do what you're looking to do. I've simply called it checkList
. It updates the array when the checkboxes change, and updates the checkboxes when the array changes.
app.directive('checkList', function() {
return {
scope: {
list: '=checkList',
value: '@'
},
link: function(scope, elem, attrs) {
var handler = function(setup) {
var checked = elem.prop('checked');
var index = scope.list.indexOf(scope.value);
if (checked && index == -1) {
if (setup) elem.prop('checked', false);
else scope.list.push(scope.value);
} else if (!checked && index != -1) {
if (setup) elem.prop('checked', true);
else scope.list.splice(index, 1);
}
};
var setupHandler = handler.bind(null, true);
var changeHandler = handler.bind(null, false);
elem.bind('change', function() {
scope.$apply(changeHandler);
});
scope.$watch('list', setupHandler, true);
}
};
});
Here's a controller and a view that shows how you might go about using it.
<div ng-app="myApp" ng-controller='MainController'>
<span ng-repeat="fruit in fruits">
<input type='checkbox' value="{{fruit}}" check-list='checked_fruits'> {{fruit}}<br />
</span>
<div>The following fruits are checked: {{checked_fruits | json}}</div>
<div>Add fruit to the array manually:
<button ng-repeat="fruit in fruits" ng-click='addFruit(fruit)'>{{fruit}}</button>
</div>
</div>
app.controller('MainController', function($scope) {
$scope.fruits = ['apple', 'orange', 'pear', 'naartjie'];
$scope.checked_fruits = ['apple', 'pear'];
$scope.addFruit = function(fruit) {
if ($scope.checked_fruits.indexOf(fruit) != -1) return;
$scope.checked_fruits.push(fruit);
};
});
(The buttons demonstrate that changing the array will also update the checkboxes.)
Finally, here is an example of the directive in action on Plunker: http://plnkr.co/edit/3YNLsyoG4PIBW6Kj7dRK?p=preview
value: '@'
by value: '=ngValue'
Based on answers in this thread I've created checklist-model directive that covers all cases:
simple array of primitives
array of objects (pick id or whole object)
object properties iteration
For topic-starter case it would be:
<label ng-repeat="fruit in ['apple', 'orange', 'pear', 'naartjie']">
<input type="checkbox" checklist-model="selectedFruits" checklist-value="fruit"> {{fruit}}
</label>
selectedFruits
.
Using a string of $index
can help to use a hashmap of selected values:
<ul>
<li ng-repeat="someItem in someArray">
<input type="checkbox" ng-model="someObject[$index.toString()]" />
</li>
</ul>
This way the ng-model object gets updated with the key representing the index.
$scope.someObject = {};
After a while $scope.someObject
should look something like:
$scope.someObject = {
0: true,
4: false,
1: true
};
This method won't work for all situations, but it is easy to implement.
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.
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).
The following solution seems like a good option,
<label ng-repeat="fruit in fruits">
<input
type="checkbox"
ng-model="fruit.checked"
ng-value="true"
> {{fruit.fruitName}}
</label>
And in controller model value fruits
will be like this
$scope.fruits = [
{
"name": "apple",
"checked": true
},
{
"name": "orange"
},
{
"name": "grapes",
"checked": true
}
];
I have adapted Yoshi's accepted answer to deal with complex objects (instead of strings).
HTML
<div ng-controller="TestController">
<p ng-repeat="permission in allPermissions">
<input type="checkbox" ng-checked="selectedPermissions.containsObjectWithProperty('id', permission.id)" ng-click="toggleSelection(permission)" />
{{permission.name}}
</p>
<hr />
<p>allPermissions: | <span ng-repeat="permission in allPermissions">{{permission.name}} | </span></p>
<p>selectedPermissions: | <span ng-repeat="permission in selectedPermissions">{{permission.name}} | </span></p>
</div>
JavaScript
Array.prototype.indexOfObjectWithProperty = function(propertyName, propertyValue)
{
for (var i = 0, len = this.length; i < len; i++) {
if (this[i][propertyName] === propertyValue) return i;
}
return -1;
};
Array.prototype.containsObjectWithProperty = function(propertyName, propertyValue)
{
return this.indexOfObjectWithProperty(propertyName, propertyValue) != -1;
};
function TestController($scope)
{
$scope.allPermissions = [
{ "id" : 1, "name" : "ROLE_USER" },
{ "id" : 2, "name" : "ROLE_ADMIN" },
{ "id" : 3, "name" : "ROLE_READ" },
{ "id" : 4, "name" : "ROLE_WRITE" } ];
$scope.selectedPermissions = [
{ "id" : 1, "name" : "ROLE_USER" },
{ "id" : 3, "name" : "ROLE_READ" } ];
$scope.toggleSelection = function toggleSelection(permission) {
var index = $scope.selectedPermissions.indexOfObjectWithProperty('id', permission.id);
if (index > -1) {
$scope.selectedPermissions.splice(index, 1);
} else {
$scope.selectedPermissions.push(permission);
}
};
}
Working example: http://jsfiddle.net/tCU8v/
<input type="checkbox">
without a wrapping or matching <label>
! Now your users have to click on the actual checkbox instead of the text next to the checkbox, which is much harder and is bad usability.
Another simple directive could be like:
var appModule = angular.module("appModule", []);
appModule.directive("checkList", [function () {
return {
restrict: "A",
scope: {
selectedItemsArray: "=",
value: "@"
},
link: function (scope, elem) {
scope.$watchCollection("selectedItemsArray", function (newValue) {
if (_.contains(newValue, scope.value)) {
elem.prop("checked", true);
} else {
elem.prop("checked", false);
}
});
if (_.contains(scope.selectedItemsArray, scope.value)) {
elem.prop("checked", true);
}
elem.on("change", function () {
if (elem.prop("checked")) {
if (!_.contains(scope.selectedItemsArray, scope.value)) {
scope.$apply(
function () {
scope.selectedItemsArray.push(scope.value);
}
);
}
} else {
if (_.contains(scope.selectedItemsArray, scope.value)) {
var index = scope.selectedItemsArray.indexOf(scope.value);
scope.$apply(
function () {
scope.selectedItemsArray.splice(index, 1);
});
}
}
console.log(scope.selectedItemsArray);
});
}
};
}]);
The controller:
appModule.controller("sampleController", ["$scope",
function ($scope) {
//#region "Scope Members"
$scope.sourceArray = [{ id: 1, text: "val1" }, { id: 2, text: "val2" }];
$scope.selectedItems = ["1"];
//#endregion
$scope.selectAll = function () {
$scope.selectedItems = ["1", "2"];
};
$scope.unCheckAll = function () {
$scope.selectedItems = [];
};
}]);
And the HTML:
<ul class="list-unstyled filter-list">
<li data-ng-repeat="item in sourceArray">
<div class="checkbox">
<label>
<input type="checkbox" check-list selected-items-array="selectedItems" value="{{item.id}}">
{{item.text}}
</label>
</div>
</li>
I'm also including a Plunker: http://plnkr.co/edit/XnFtyij4ed6RyFwnFN6V?p=preview
You don't have to write all that code. AngularJS will keep the model and the checkboxes in sync simply by using ngTrueValue and ngFalseValue
Codepen here: http://codepen.io/paulbhartzog/pen/kBhzn
Code snippet:
<p ng-repeat="item in list1" class="item" id="{{item.id}}">
<strong>{{item.id}}</strong> <input name='obj1_data' type="checkbox" ng-model="list1[$index].data" ng-true-value="1" ng-false-value="0"> Click this to change data value below
</p>
<pre>{{list1 | json}}</pre>
Check out this directive that manages effectively lists of checkboxes. I hope it works for you. CheckList Model
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.
I like Yoshi's answer. I enhanced it so You can use the same function for multiple lists.
<label ng-repeat="fruitName in fruits">
<input
type="checkbox"
name="selectedFruits[]"
value="{{fruitName}}"
ng-checked="selection.indexOf(fruitName) > -1"
ng-click="toggleSelection(fruitName, selection)"> {{fruitName}}
</label>
<label ng-repeat="veggieName in veggies">
<input
type="checkbox"
name="selectedVeggies[]"
value="{{veggieName}}"
ng-checked="veggieSelection.indexOf(veggieName) > -1"
ng-click="toggleSelection(veggieName, veggieSelection)"> {{veggieName}}
</label>
app.controller('SimpleArrayCtrl', ['$scope', function SimpleArrayCtrl($scope) {
// fruits
$scope.fruits = ['apple', 'orange', 'pear', 'naartjie'];
$scope.veggies = ['lettuce', 'cabbage', 'tomato']
// selected fruits
$scope.selection = ['apple', 'pear'];
$scope.veggieSelection = ['lettuce']
// toggle selection for a given fruit by name
$scope.toggleSelection = function toggleSelection(selectionName, listSelection) {
var idx = listSelection.indexOf(selectionName);
// is currently selected
if (idx > -1) {
listSelection.splice(idx, 1);
}
// is newly selected
else {
listSelection.push(selectionName);
}
};
}]);
http://plnkr.co/edit/KcbtzEyNMA8s1X7Hja8p?p=preview
If you have multiple checkboxes on the same form
The controller code
vm.doYouHaveCheckBox = ['aaa', 'ccc', 'bbb'];
vm.desiredRoutesCheckBox = ['ddd', 'ccc', 'Default'];
vm.doYouHaveCBSelection = [];
vm.desiredRoutesCBSelection = [];
View code
<div ng-repeat="doYouHaveOption in vm.doYouHaveCheckBox">
<div class="action-checkbox">
<input id="{{doYouHaveOption}}" type="checkbox" value="{{doYouHaveOption}}" ng-checked="vm.doYouHaveCBSelection.indexOf(doYouHaveOption) > -1" ng-click="vm.toggleSelection(doYouHaveOption,vm.doYouHaveCBSelection)" />
<label for="{{doYouHaveOption}}"></label>
{{doYouHaveOption}}
</div>
</div>
<div ng-repeat="desiredRoutesOption in vm.desiredRoutesCheckBox">
<div class="action-checkbox">
<input id="{{desiredRoutesOption}}" type="checkbox" value="{{desiredRoutesOption}}" ng-checked="vm.desiredRoutesCBSelection.indexOf(desiredRoutesOption) > -1" ng-click="vm.toggleSelection(desiredRoutesOption,vm.desiredRoutesCBSelection)" />
<label for="{{desiredRoutesOption}}"></label>
{{desiredRoutesOption}}
</div>
</div>
Inspired from Yoshi's post above. Here is the plnkr.
(function () { angular .module("APP", []) .controller("demoCtrl", ["$scope", function ($scope) { var dc = this dc.list = [ "Selection1", "Selection2", "Selection3" ] dc.multipleSelections = [] dc.individualSelections = [] // 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. dc.addOrRemove = 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) } } } }]) })() label { display: block; }
dc.multipleSelections :- {{dc.multipleSelections}}
dc.invidualSelections :- {{dc.individualSelections}}
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; }
dc.multipleSelecitons:- {{dc.multipleSelections}}
dc.individualSelecitons:- {{dc.individualSelections}}
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});
};
Here is yet another solution. The upside of my solution:
It does not need any additional watches (which may have an impact on performance)
It does not require any code in the controller keeping it clean
The code is still somewhat short
It is requires very little code to reuse in multiple places because it is just a directive
Here is the directive:
function ensureArray(o) {
var lAngular = angular;
if (lAngular.isArray(o) || o === null || lAngular.isUndefined(o)) {
return o;
}
return [o];
}
function checkboxArraySetDirective() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
var name = attrs.checkboxArraySet;
ngModel.$formatters.push(function(value) {
return (ensureArray(value) || []).indexOf(name) >= 0;
});
ngModel.$parsers.push(function(value) {
var modelValue = ensureArray(ngModel.$modelValue) || [],
oldPos = modelValue.indexOf(name),
wasSet = oldPos >= 0;
if (value) {
if (!wasSet) {
modelValue = angular.copy(modelValue);
modelValue.push(name);
}
} else if (wasSet) {
modelValue = angular.copy(modelValue);
modelValue.splice(oldPos, 1);
}
return modelValue;
});
}
}
}
At the end then just use it like this:
<input ng-repeat="fruit in ['apple', 'banana', '...']" type="checkbox" ng-model="fruits" checkbox-array-set="{{fruit}}" />
And that is all there is. The only addition is the checkbox-array-set
attribute.
You can combine AngularJS and jQuery. For example, you need to define an array, $scope.selected = [];
, in the controller.
<label ng-repeat="item in items">
<input type="checkbox" ng-model="selected[$index]" ng-true-value="'{{item}}'">{{item}}
</label>
You can get an array owning the selected items. Using method alert(JSON.stringify($scope.selected))
, you can check the selected items.
<div ng-app='app' >
<div ng-controller='MainCtrl' >
<ul>
<li ng-repeat="tab in data">
<input type='checkbox' ng-click='change($index,confirm)' ng-model='confirm' />
{{tab.name}}
</li>
</ul>
{{val}}
</div>
</div>
var app = angular.module('app', []);
app.controller('MainCtrl',function($scope){
$scope.val=[];
$scope.confirm=false;
$scope.data=[
{
name:'vijay'
},
{
name:'krishna'
},{
name:'Nikhil'
}
];
$scope.temp;
$scope.change=function(index,confirm){
console.log(confirm);
if(!confirm){
($scope.val).push($scope.data[index]);
}
else{
$scope.temp=$scope.data[index];
var d=($scope.val).indexOf($scope.temp);
if(d!=undefined){
($scope.val).splice(d,1);
}
}
}
})
Take a look this: checklist-model.
It works with JavaScript arrays, and objects and it can use static HTML checkboxes, without ng-repeat
<label><input type="checkbox" checklist-model="roles" value="admin"> Administrator</label>
<label><input type="checkbox" checklist-model="roles" value="customer"> Customer</label>
<label><input type="checkbox" checklist-model="roles" value="guest"> Guest</label>
<label><input type="checkbox" checklist-model="roles" value="user"> User</label>
And the JavaScript side:
var app = angular.module("app", ["checklist-model"]);
app.controller('Ctrl4a', function($scope) {
$scope.roles = [];
});
A simple HTML only way of doing it:
Using this example of the @Umur Kontacı, I think in using to catch selected data throughout another object/array, like a edit page.
Catch options at the database
https://i.stack.imgur.com/77E0O.png
Toggle a some option
https://i.stack.imgur.com/erSs6.png
As example, all colors json in below:
{
"colors": [
{
"id": 1,
"title": "Preto - #000000"
},
{
"id": 2,
"title": "Azul - #005AB1"
},
{
"id": 3,
"title": "Azul Marinho - #001A66"
},
{
"id": 4,
"title": "Amarelo - #FFF100"
},
{
"id": 5,
"title": "Vermelho - #E92717"
},
{
"id": 6,
"title": "Verde - #008D2F"
},
{
"id": 7,
"title": "Cinza - #8A8A8A"
},
{
"id": 8,
"title": "Prata - #C8C9CF"
},
{
"id": 9,
"title": "Rosa - #EF586B"
},
{
"id": 10,
"title": "Nude - #E4CAA6"
},
{
"id": 11,
"title": "Laranja - #F68700"
},
{
"id": 12,
"title": "Branco - #FFFFFF"
},
{
"id": 13,
"title": "Marrom - #764715"
},
{
"id": 14,
"title": "Dourado - #D9A300"
},
{
"id": 15,
"title": "Bordo - #57001B"
},
{
"id": 16,
"title": "Roxo - #3A0858"
},
{
"id": 18,
"title": "Estampado "
},
{
"id": 17,
"title": "Bege - #E5CC9D"
}
]
}
And 2 types of data object, array
with one object and object
containing two/more object data:
Two items selected catched at the database: [{"id":12,"title":"Branco - #FFFFFF"},{"id":16,"title":"Roxo - #3A0858"}]
One item selected catched at the database: {"id":12,"title":"Branco - #FFFFFF"}
And here, my javascript code:
/**
* Add this code after catch data of database.
*/
vm.checkedColors = [];
var _colorObj = vm.formData.color_ids;
var _color_ids = [];
if (angular.isObject(_colorObj)) {
// vm.checkedColors.push(_colorObj);
_color_ids.push(_colorObj);
} else if (angular.isArray(_colorObj)) {
angular.forEach(_colorObj, function (value, key) {
// vm.checkedColors.push(key + ':' + value);
_color_ids.push(key + ':' + value);
});
}
angular.forEach(vm.productColors, function (object) {
angular.forEach(_color_ids, function (color) {
if (color.id === object.id) {
vm.checkedColors.push(object);
}
});
});
/**
* Add this code in your js function initialized in this HTML page
*/
vm.toggleColor = function (color) {
console.log('toggleColor is: ', color);
if (vm.checkedColors.indexOf(color) === -1) {
vm.checkedColors.push(color);
} else {
vm.checkedColors.splice(vm.checkedColors.indexOf(color), 1);
}
vm.formData.color_ids = vm.checkedColors;
};
My Html code:
<div class="checkbox" ng-repeat="color in productColors">
<label>
<input type="checkbox"
ng-checked="checkedColors.indexOf(color) != -1"
ng-click="toggleColor(color)"/>
<% color.title %>
</label>
</div>
<p>checkedColors Output:</p>
<pre><% checkedColors %></pre>
[Edit] Refactored code below:
function makeCheckedOptions(objectOptions, optionObj) {
var checkedOptions = [];
var savedOptions = [];
if (angular.isObject(optionObj)) {
savedOptions.push(optionObj);
} else if (angular.isArray(optionObj)) {
angular.forEach(optionObj, function (value, key) {
savedOptions.push(key + ':' + value);
});
}
angular.forEach(objectOptions, function (object) {
angular.forEach(savedOptions, function (color) {
if (color.id === object.id) {
checkedOptions.push(object);
}
});
});
return checkedOptions;
}
And call new method as below:
vm.checkedColors = makeCheckedOptions(productColors, vm.formData.color_ids);
That's it!
I've put an array in the controller.
$scope.statuses = [{ name: 'Shutdown - Reassessment Required' },
{ name: 'Under Construction' },
{ name: 'Administrative Cancellation' },
{ name: 'Initial' },
{ name: 'Shutdown - Temporary' },
{ name: 'Decommissioned' },
{ name: 'Active' },
{ name: 'SO Shutdown' }]
On the markup I've put something like following
<div ng-repeat="status in $scope.statuses">
<input type="checkbox" name="unit_status" ng-model="$scope.checkboxes[status.name]"> {{status.name}}
<br>
</div>
{{$scope.checkboxes}}
The output was the following, in the controller I just needed to check whether its true or false; true for checked, absent/false for unchecked.
{
"Administrative Cancellation":true,
"Under Construction":true,
"Shutdown - Reassessment Required":true,
"Decommissioned":true,
"Active":true
}
Hope this helps.
I think the following way is more clear and useful for nested ng-repeats. Check it out on Plunker.
<html ng-app="plunker">
<head>
<title>Test</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.4/angular.min.js"></script>
</head>
<body ng-controller="MainCtrl">
<div ng-repeat="tab in mytabs">
<h1>{{tab.name}}</h1>
<div ng-repeat="val in tab.values">
<input type="checkbox" ng-change="checkValues()" ng-model="val.checked"/>
</div>
</div>
<br>
<pre> {{selected}} </pre>
<script>
var app = angular.module('plunker', []);
app.controller('MainCtrl', function ($scope,$filter) {
$scope.mytabs = [
{
name: "tab1",
values: [
{ value: "value1",checked:false },
{ value: "value2", checked: false },
{ value: "value3", checked: false },
{ value: "value4", checked: false }
]
},
{
name: "tab2",
values: [
{ value: "value1", checked: false },
{ value: "value2", checked: false },
{ value: "value3", checked: false },
{ value: "value4", checked: false }
]
}
]
$scope.selected = []
$scope.checkValues = function () {
angular.forEach($scope.mytabs, function (value, index) {
var selectedItems = $filter('filter')(value.values, { checked: true });
angular.forEach(selectedItems, function (value, index) {
$scope.selected.push(value);
});
});
console.log($scope.selected);
};
});
</script>
</body>
</html>
Here is the jsFillde link for the same, http://jsfiddle.net/techno2mahi/Lfw96ja6/.
This uses the directive which is available for download at http://vitalets.github.io/checklist-model/.
This is the good to have directive as your application will need this functionality much often.
The code is below:
HTML:
<div class="container">
<div class="ng-scope" ng-app="app" ng-controller="Ctrl1">
<div class="col-xs-12 col-sm-6">
<h3>Multi Checkbox List Demo</h3>
<div class="well"> <!-- ngRepeat: role in roles -->
<label ng-repeat="role in roles">
<input type="checkbox" checklist-model="user.roles" checklist-value="role"> {{role}}
</label>
</div>
<br>
<button ng-click="checkAll()">check all</button>
<button ng-click="uncheckAll()">uncheck all</button>
<button ng-click="checkFirst()">check first</button>
<div>
<h3>Selected User Roles </h3>
<pre class="ng-binding">{{user.roles|json}}</pre>
</div>
<br>
<div><b/>Provided by techno2Mahi</b></div>
</div>
JavaScript
var app = angular.module("app", ["checklist-model"]);
app.controller('Ctrl1', function($scope) {
$scope.roles = [
'guest',
'user',
'customer',
'admin'
];
$scope.user = {
roles: ['user']
};
$scope.checkAll = function() {
$scope.user.roles = angular.copy($scope.roles);
};
$scope.uncheckAll = function() {
$scope.user.roles = [];
};
$scope.checkFirst = function() {
$scope.user.roles.splice(0, $scope.user.roles.length);
$scope.user.roles.push('guest');
};
});
<div>
than closing, </div>
. Have you left something out?
Try my baby:
**
myApp.filter('inputSelected', function(){
return function(formData){
var keyArr = [];
var word = [];
Object.keys(formData).forEach(function(key){
if (formData[key]){
var keyCap = key.charAt(0).toUpperCase() + key.slice(1);
for (var char = 0; char<keyCap.length; char++ ) {
if (keyCap[char] == keyCap[char].toUpperCase()){
var spacedLetter = ' '+ keyCap[char];
word.push(spacedLetter);
}
else {
word.push(keyCap[char]);
}
}
}
keyArr.push(word.join(''))
word = [];
})
return keyArr.toString();
}
})
**
Then for any ng-model with checkboxes, it will return a string of all the input you selected:
<label for="Heard about ITN">How did you hear about ITN?: *</label><br>
<label class="checkbox-inline"><input ng-model="formData.heardAboutItn.brotherOrSister" type="checkbox" >Brother or Sister</label>
<label class="checkbox-inline"><input ng-model="formData.heardAboutItn.friendOrAcquaintance" type="checkbox" >Friend or Acquaintance</label>
{{formData.heardAboutItn | inputSelected }}
//returns Brother or Sister, Friend or Acquaintance
Success story sharing
value="{{fruit.name}}"
andng-checked="fruit.checked"
are superfluous, since ng-model is used.