Bind element if css class exists - javascript

I have a group of 3 bootstrap styled checkboxes like so:
<div class="btn-group" data-toggle="buttons">
<label class="btn btn-primary btn-sm" data-bind=""><input type="checkbox">Checkbox 1</label>
<label class="btn btn-primary btn-sm"><input type="checkbox">Checkbox 2</label>
<label class="btn btn-primary btn-sm"><input type="checkbox">Checkbox 3</label>
</div>
At runtime if the first checkbox is pressed, when I inspect the element it gets an active css class appended to it:
<label class="btn btn-primary btn-sm active" >
How should my data-bind="" property look like if I want a function to execute when the input receives the active class? I would also want the opposite to happen as well. When the active class is no longer present, a function must also be called.
I can't use a click binding on the checkbox because it doesn't work because of bootstrap's way of "ticking" a checkbox.
Thank you (demo - http://jsfiddle.net/H7Js6/)

knockout is about having a viewmodel that represents your UI. Instead of a click binding, you can have checked binding and use the subscribe function:
<label class="btn btn-primary btn-sm" data-bind="">
<input type="checkbox" data-bind="checked: cb1" />Checkbox 1
</label>
And in the js:
var viewmodel = function () {
this.cb1 = ko.observable();
this.cb1.subscribe(function (newValue) {
//your code here gets called every time the checked status changes
// use newValue to know the new state
});
}
Demo
Update
Thank you for your fiddle, it always helps to have one.
Indeed, in this case the checked is not changed when the bootstrap css is loaded (if you remove the resource, you'll see it works).
To workaround it, you can have a custom binding handler that will check the presence of the css class for you:
ko.bindingHandlers.bootstrapCheckbox = {
init: function (element, valueAccessor, allBindingAccessor, viewModel,
bindingContext) {
if (ko.isObservable(allBindingAccessor().value)) {
$(element).change(function () {
//invert it because called before the class is added/removed :(
allBindingAccessor().value(!$(element).hasClass("active"));
});
}
allBindingAccessor().value($(element).hasClass("active")); //init value
}
}
Usage:
<label class="btn btn-primary btn-sm"
data-bind="bootstrapCheckbox: true, value: cb1">
<input type="checkbox" />Checkbox 1
</label>
Then keep the code from the first part of this answer (the subscribe).
Demo

Understanding there's already a good answer and trying to get how it was done I thought of using the already existing click binding for this, which may be another option (not saying it's better at all)
var vm = function(){
this.checkedButtons = ko.observableArray([]);
this.isActive = function(item, event){
if (!$(event.target).hasClass("active")){
this.checkedButtons.push(event.target);
}
else{
this.checkedButtons.pop();
}
};
};
ko.applyBindings(new vm());
Usage:
<div class="btn-group" data-toggle="buttons">
<label id="label1" class="btn btn-primary btn-sm" data-bind="click: isActive"><input id="input1" type="checkbox">Checkbox 1</label>
<label class="btn btn-primary btn-sm" data-bind="click: isActive"><input type="checkbox">Checkbox 2</label>
<label class="btn btn-primary btn-sm" data-bind="click: isActive"><input type="checkbox">Checkbox 3</label>
</div>
<div>How many buttons are clicked?
<span data-bind="text: checkedButtons().length "></span>
</div>
Fiddle

If you're using jquery, you can bind change event on the radio buttons themselves
$(".btn-group input[type=checkbox]").on("change",function(){
//you can do whatever you want here
});

Related

Disable radio button in bootstrap 3?

How can I disable Bootstrap 3 radio buttons? If I start with the BS3 example and add disabled="disabled" to each input element, there are no changes in appearance or behavior:
<div class="container">
<div class="btn-group" data-toggle="buttons">
<label class="btn btn-primary active">
<input type="radio" name="options" id="option1" autocomplete="off" checked disabled="disabled">Radio 1 (preselected)</label>
<label class="btn btn-primary">
<input type="radio" name="options" id="option2" autocomplete="off" disabled="disabled">Radio 2</label>
<label class="btn btn-primary">
<input type="radio" name="options" id="option3" autocomplete="off" disabled="disabled">Radio 3</label>
</div>
Demo: JSFiddle.
I guess this is because the disabled attribute is only applied to the now-invisible button and not the clickable text label, but I don't see anything in the BS3 docs about this.
Add disabled class to the label like this
<div class="btn-group" data-toggle="buttons">
<label class="btn btn-primary disabled">
<input type="checkbox" autocomplete="off"> Checkbox 1 (pre-checked)
</label>
<label class="btn btn-primary active disabled">
<input type="checkbox" autocomplete="off"> Checkbox 2
</label>
<label class="btn btn-primary disabled">
<input type="checkbox" autocomplete="off"> Checkbox 3
</label>
</div>
Here is a demo
As mentioned by #giammin in the comments to the accepted answer, setting 'disabled' on the input elements doesn't work in 3.3.6 of bootstrap. (Current version at time of publication of this answer).
I was having exactly the same issue, and my solution was to use the CSS property "pointer events". This makes sure the element and children are never a target of click events. However this is not a foolproof solution - users can still tab in and use space to click the hidden elements on a desktop browser.
.disabled-group
{
pointer-events: none;
}
If you set this on your '.btn-group' element, you'll completely disable
<div class="btn-group disabled-group" data-toggle="buttons">
<label class="btn btn-primary disabled">
<input type="checkbox" autocomplete="off"> Checkbox 1 (pre-checked)
</label>
<label class="btn btn-primary disabled">
<input type="checkbox" autocomplete="off"> Checkbox 2
</label>
<label class="btn btn-primary disabled">
<input type="checkbox" autocomplete="off"> Checkbox 3
</label>
</div>
The '.disabled' class is then optional - use it for graying out and 'cursor: not-allowed;' property.
The discussion of the fix solution is at this source:
https://github.com/twbs/bootstrap/issues/16703
For radio button groups, add class disabled to the one you wish disabled.
Make sure you have something like this code:
$('.btn-group').on("click", ".disabled", function(event) {
event.preventDefault();
return false;
});
This will get all your .disabled classed buttons inside the button groups also disabled. This works also for radio type button groups.
You can use the above to disable an input[type='radio'] that is inside a label (bootstrap 3 style),
$("input[name='INPUT_RADIO_NAME']").prop("disabled", true);
$("input[name='INPUT_RADIO_NAME']").closest("div").css("pointer-events", "none");
The above to enable again,
$("input[name='INPUT_RADIO_NAME']").prop("disabled", false);
$("input[name='INPUT_RADIO_NAME']").closest("div").css("pointer-events", "auto");
You can also extend JQuery and create a dummy disable method (that you could upgrade with more functionality) like this,
(function ($) {
$.fn.disableMe = function () {
// Validate.
if ($.type(this) === "undefined")
return false;
// Disable only input elements.
if ($(this).is("input") || $(this).is("textarea")) {
// In case it is a radio inside a label.
if ($(this).is("[type='radio']") && $(this).parent().is("label.btn")) {
$("input[name='safeHtml']").closest("label").addClass("disabled");
$(this).closest("div").css("pointer-events", "none");
}
// General input disable.
$(this).prop("disabled", true);
}
};
$.fn.enableMe = function () {
// Validate.
if ($.type(this) === "undefined")
return false;
// Enable only input elements.
if ($(this).is("input") || $(this).is("textarea")) {
// In case it is a radio inside a label.
if ($(this).is("[type='radio']") && $(this).parent().is("label.btn")) {
$("input[name='safeHtml']").closest("label").removeClass("disabled");
$(this).closest("div").css("pointer-events", "auto");
}
// General input enable.
$(this).prop("disabled", false);
}
};
$.fn.toggleDisable = function () {
if ($.type(this) === "undefined")
return false;
// Toggle only input elements.
if ($(this).is("input") || $(this).is("textarea")) {
var isDisabled = $(this).is(":disabled");
// In case it is a radio inside a label.
if ($(this).is("[type='radio']") && $(this).parent().is("label.btn")) {
$("input[name='safeHtml']").closest("label").toggleClass("disabled");
$(this).closest("div").css("pointer-events", isDisabled ? "auto" : "none");
}
// General input enale.
$(this).prop("disabled", !isDisabled);
}
};
}(jQuery));
Usage example,
$("input[name='INPUT_RADIO_NAME']").disableMe();
$("input[name='INPUT_RADIO_NAME']").enableMe();
$("input[name='INPUT_RADIO_NAME']").toggleDisable();
In bootstrap if you want to disabled any input type or button, You just have to add bootstrap's .disabled class then your button become disabled.
Like this
<input type="radio" class="btn btn-primary disabled">Primary Button</button>

Simple Angular radio buttons not working... seem broken?

This works:
<h4>Radio & Uncheckable Radio</h4>
<pre>{{radioModel || 'null'}}</pre>
<div class="btn-group">
<label class="btn btn-primary" ng-model="radioModel" btn-radio="'Left'">Left</label>
<label class="btn btn-primary" ng-model="radioModel" btn-radio="'Middle'">Middle</label>
<label class="btn btn-primary" ng-model="radioModel" btn-radio="'Right'">Right</label>
</div>
This doesn't work
{{radioModel || 'null'}}
<div class="btn-group">
<label class="btn btn-primary" data-ng-repeat="store in global.user.store" ng-model="radioModel" btn-radio="{{store}}" uncheckable>{{store}}</label><br>
</div>
If you select one radio button, the other radiobuttons don't de-select. Instead of having one radio button checked at a time, all 3 can be checked! And the {{radioModel}} won't display any value. For the first example, {{radioModel}} would display 'Left,' 'Right,' or 'Middle' depending on the value of btn-radio.
It's like data-ng-repeat="store in global.user.store" breaks the button behavior!
Try setting the scope variable with a dot, like if it an object.
$scope.radio = {model: null}; //for example
And use always radio.model instead of radioModel.
This is because the way the scope inheritance works each ng-model of the ng-repeat will generate a new scope. With the 'dot' rule you want have this problem.
Here is more information https://github.com/angular/angular.js/wiki/Understanding-Scopes
Try removing the {{}} in the btn-radio attribute :
<label class="btn btn-primary" data-ng-repeat="store in global.user.store" ng-model="radioModel" btn-radio="store" uncheckable>{{store}}</label>

AngularJS: How to change radio button view when model changes?

Consider the HTML as
<div class="btn-group col-lg-3" data-toggle="buttons" data-ng-model="transaction.debit" required>
<label class="btn btn-default" data-ng-click="setDebitTransaction('true')">
<input type="radio">Debit
</label>
<label class="btn btn-default" data-ng-click="setDebitTransaction('false')">
<input type="radio">Credit
</label>
<div>
and my Controller looks like
$scope.transaction = {};
$scope.setDebitTransaction = function(value) {
$scope.transaction.debit = value;
console.log('Debit = ', $scope.transaction.debit);
};
What I want?
- When I click on radio button I see that the $scope.transaction.debit is correctly set and that the corresponding radio button is enabled
- But when my model changes its value from backend processing, I see that $scope.transaction.debit is correctly set but corresponding radio element is not enabled
Question
- How can I enable the radio button based on value in $scope.transaction.debit?
DEMO
I have put this on plunker
I assume what you are trying to do is get the appropriate button in the btn-group to change its state to "active" (bootstrap style class). To do this, there are probably a million ways, here is one:
Use the ng-class directive in angular, to inject a class to the btn div, based on some $scope attribute (in your case $scope.transaction.debit).
Here is how that might look in code:
<label class="btn btn-default" ng-class="{'active': transaction.debit}" data-ng-click="setDebitTransaction('true')">
<input type="radio">Debit
</label>
<label class="btn btn-default" ng-class="{'active': !transaction.debit}" data-ng-click="setDebitTransaction('false')">
<input type="radio">Credit
</label>
Updated plunker.
Set the active class via ng-class on your labels like so:
<label class="btn btn-default" ng-class="{active: transaction.debit}" data-ng-click="setDebitTransaction('true')">
<input type="radio">Debit
</label>
<label class="btn btn-default" ng-class="{active: !transaction.debit}" data-ng-click="setDebitTransaction('false')">
<input type="radio">Credit
</label>
Plunker here: http://plnkr.co/edit/tUzF4J9ixEnKxLNdI1Bm

check all checkboxes and reverse if one item is checked

I have a form with multiple groups of checkboxes. I have one checkbox in each group that is a select/deselect all checkbox. I have been using the following function to enact a selectall deselectall and changing class on each of the inputs parents item, a button. What is the best way going forward to remove the checkall selection of the checkbox and remove and add a class if one item from the list that is not the checkall checkbox is chosen, and then reversed if person chooses all checkboxes or the checkall checkbox. I have been saving $(this) as a variable. Is this going to be an issue?
.html
<div class="panel-body">
<div class="col-xs-6 col-sm-4 margin-bottom-sm">
<label for="checkall4" class="btn btn-custom btn-sm btn-block">
<input type="checkbox" name="checkall4" id="checkall4" data-mini="true" class="checkall" checked>
Select/Deselect All</label>
</div>
<div class="col-xs-6 col-sm-4 margin-bottom-sm">
<label for="within1" class="btn btn-custom btn-sm btn-block">
<input type="checkbox" name="within1" value="1" checked="checked" id="within1"/>
Within 1km</label>
</div>
<div class="col-xs-6 col-sm-4 margin-bottom-sm">
<label for="within2" class="btn btn-custom btn-sm btn-block">
<input type="checkbox" name="within2" value="2" checked="checked" id="within2"/>
Within 2km</label>
</div>
</div>
.js
$('.checkall').change(function() {
var $this = $(this);
var $allBoxes = $this.closest('.panel-body').find(':checkbox');
if ($this.prop('checked')) {
$allBoxes.prop('checked', true);
$allBoxes.parent().removeClass('btn-default').addClass('btn-custom');
} else {
$allBoxes.prop('checked', false);
$allBoxes.parent().removeClass('btn-custom').addClass('btn-default');
}
});
Add another handler for handler non checkall checkboxes
$('.panel-body input[type="checkbox"]:not(.checkall)').change(function () {
var $this = $(this),
$body = $this.closest('.panel-body');
var $allBoxes = $body.find(':checkbox:not(.checkall)');
$body.find('.checkall').prop('checked', $allBoxes.not(':checked').length == 0);
})
Demo: Fiddle
use this javascript
$(document).ready(function () {
$(".checkall").click(function () {
$(".classofcheckbox").prop('checked', $(this).prop('checked'));
});
});
DEMO

Getting active buttons in button-group (bootstrap)

I have a button group and am willing to update some other field on change according to the active buttons.
See the jsfiddle here
This is the HTML, copied from the documentation:
<div class="btn-group arrActiviteit arrUpdate" data-toggle="buttons">
<label class="btn btn-primary active" data-wat='foo'>
<input type="checkbox"> Item 1
</label>
<label class="btn btn-primary" data-wat='bar'>
<input type="checkbox"> Item 2
</label>
<label class="btn btn-primary" data-wat='something'>
<input type="checkbox"> item 3
</label>
<label class="btn btn-primary" data-wat='orElse'>
<input type="checkbox"> item 4
</label>
</div>
The Button row acts like it should do.
Then I watch for a click event on the .arrUpdate div for change. I've got multiple button groups which all have the .arrUpdate class. That's the reason for the second class: .arrActiviteit
$('.arrUpdate').click(function(e){
val = ''; // for holding the temporary values
$('.arrActiviteit label').each(function(key, value){
if(value.className.indexOf('active') >=0){
val += value.dataset.wat
}
})
// just for debug reasons.
$('#hierHier').html(val);
})
But it appears that the 'active' class gets added after the click event is fired. So the value in #hierHier is always behind one click, so to say.
How can I resolve this?
Or is there a better way to retrieve all the active buttons in this checkbox-array?
SOLVED
update: better solution Twitter Bootstrap onclick event on buttons-radio
http://jsfiddle.net/hA423/7/
I solved it using a timeout to make your function run after bootstrap events...
There must be some other ways to do it...
$('.btn').on('click',function(e){
setTimeout(count);
})

Categories