Reputation: 2062
I have an observableArray binded to a pair of checkboxes.The array is supposed to change when selecting/deselecting the checkboxes, as it is written in the documentation:
Special consideration is given if your parameter resolves to an array. In this case, KO will set the element to be checked if the value matches an item in the array, and unchecked if it is not contained in the array.
When the user checks or unchecks the checkbox, KO will add or remove the value from the array accordingly.
But the array is not changing.
Here is the knockout code for the array:
self.filterByUserType = ko.observableArray(["Teacher","Student"]);
And here the html bindings:
<div id="LLClaimsButtons" class="btn-group" data-toggle="buttons">
<div class="btn">
<input data-bind="checked: filterByUserType" type="checkbox" value="Teacher" title="Profesor/a"><span class="fa fa-mortar-board"></span>
</div>
<div class="btn">
<input data-bind="checked: filterByUserType" type="checkbox" value="Student" title="Alumno/a"><span class="fa fa-user"></span>
</div>
</div>
And here a little test:
<div data-bind="foreach: filterByUserType">
<div data-bind="text: $data"></div>
</div>
And well, it doesn't matter what i do with checkboxes tht the array is always the same.
Upvotes: 0
Views: 67
Reputation: 2062
While @Jamiec answer is perfectly correct, there is a problem if the filterByUserType
array is modified away of the 'click' event: then the status of the button (controlled by Bootstrap on click) will be different of the real state of the array.
So, partially based on Jamiec's solution (+1 for that), i've implemented a custom binding that is working fine to me. Here it is:
self.filterByUserType = ko.observableArray(["Teacher","Student"]);
ko.bindingHandlers.checkboxButton = {
init: function (element, valueAccessor) {
var value = valueAccessor();
var $element = $(element);
var $inputElement = $(element).find('input');
if ($inputElement) {
$element.on('click', function () {
var data = $inputElement.prop('value');
$element.hasClass("active") ? value.remove(data) : value.push(data);
});
}
},
update: function (element, valueAccessor) {
var value = valueAccessor();
var $element = $(element);
var $inputElement = $(element).find('input');
var data = $inputElement.prop('value');
value().indexOf(data) > -1 ? $element.addClass('active') : $element.removeClass('active');
}
};
For now, this binding must be set in a checkbox input's parent, have an observableArray as main attribute and the "value" property with the same string as an array's item.
Here is how i'm using it:
<div id="LLClaimsButtons">
<div class="btn" data-bind="checkboxButton: filterByUserType">
<input type="checkbox" value="Teacher" title="Profesor/a"><span class="fa fa-mortar-board"></span>
</div>
div class="btn" data-bind="checkboxButton: filterByUserType">
<input type="checkbox" value="Student" title="Alumno/a"><span class="fa fa-user"></span>
</div>
</div>
As you can see, i'm not using Bootstrap's data-toggle:buttons
anymore since i toggle the 'active' class inside the binding.
Upvotes: 0
Reputation: 136154
There doesn't seem to be much point to the checkbox inside your bootstrap buttons - you may as well just bind the click on your buttons to a function in your view model which does the work of adding/removing an item
function ViewModel(){
var self = this;
self.filterByUserType = ko.observableArray(["Teacher","Student"]);
self.click = function(data){
self.filterByUserType.indexOf(data) > -1 ? self.filterByUserType.remove(data) : self.filterByUserType.push(data)
}
}
ko.applyBindings(new ViewModel())
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="LLClaimsButtons" class="btn-group" data-toggle="buttons">
<div class="btn" data-bind="click:function(){click('Teacher')}">
<span class="fa fa-mortar-board"></span>
</div>
<div class="btn" data-bind="click:function(){click('Student')}">
<span class="fa fa-user"></span>
</div>
</div>
<hr>
<div data-bind="foreach: filterByUserType">
<div data-bind="text: $data"></div>
</div>
Note you might need to view that snippet in fullscreen mode - the script error does not affect execution but gets in the way.
Upvotes: 1