Replacing Radio Buttons with a Button Group using Bootstrap and #KnockoutJS Replacing Radio Buttons with a Button Group using Bootstrap and #KnockoutJS

Radio buttons are hard-to-see, not easy to select, and let's face it, quite mundane. You would like to JavaScript String replace() these radio buttons with a group of buttons that represent the same functionality, e.g. only one of the options may be selected at any given time.

Leveraging Bootstrap which provides many incredibly styled components for buttons, alert boxes, tables, forms, etc... regular radio buttons will be replaced by a button group (see screenshot below). This Knockout.js tutorial will be used to create a custom data binding that will make the group of buttons act like regular radio buttons (with a nicer look of course).

radiobuttongroup

This example assumes you have a basic understanding of both Bootstrap and Knockout.js. If you don't, feel free to explore my latest book ASP.NET MVC 5 with Bootstrap and Knockout.js for a great introduction, plus many more examples.

The versions used for this example are 3.3.4 for Bootstrap and 3.3 for Knockout.js. This example should be compatible with older versions of these frameworks.


Creating a custom Knockout.js data binding

Before getting started, the frameworks required must be setup. Bootstrap can be installed either via their CDN or downloaded. This example will use the CDN; however, I suggest you use the option that bests suits your needs. Knockout.js has been downloaded and saved into the same location as where the example lives. Ensure you update this location based on your project's location. And finally, a little bit of jQuery tutorial is used within the Knockout Custom Binding. Once again, this example is leveraging the CDN; however, you may download and include it if you like.

For this example to work, it requires two things. A group of buttons that will contain what would be the options if they were radio buttons and a Knockout observable value that will be used in the data-binding. This observable will contain the selected option. Below contains the HTML markup and the extremely basic Knockout ViewModel.


<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
</head>
<body>
<div class="btn-group">
<button type="button" class="btn btn-default" data-bind="radioButtonGroup: selectedOption, radioValue: 'option1'">Option 1</button>
<button type="button" class="btn btn-default" data-bind="radioButtonGroup: selectedOption, radioValue: 'option2'">Option 2</button>
<button type="button" class="btn btn-default" data-bind="radioButtonGroup: selectedOption, radioValue: 'option3'">Option 3</button>
</div>
<script src="knockout.js"></script>
<script src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
<script>
function ViewModel() {
var self = this;
self.selectedOption = ko.observable();
};
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
</script>
</body>
</html>

This example won't work just yet. If you look closely, each of the HTML buttons contain a data-binding called radioButtonGroup (this will be defined momentarily). This is the custom data binding that will accomplish are fancy button group.

Supplied to the new data binding is the observable variable, aptly named, selectedOption. A second value is supplied as well named radioValue. This should be set to the value you wish the selectedOption variable to contain when the user presses that button.

To complete this example, the custom binding needs to be created. Custom bindings are added under the ko.bindingHandlers namespace. A binding handler is defined by creating an init and update function. Either are optional, but at least one must be defined.

The init function is called when Knockout is first data bound to the page. This is where you would create event listeners, etc. The update function is called every time the value changes (including on first load). In case it might help understand certain things about Javascript be sure to read about difference between location.href and location.replace. This function would be used if you wished to perform specific actions each time the value changed.

The radioButtonGroup custom binding only requires the init function because event listeners for the click event will be used to track all changes. Custom bindings are very similar to creating a Knockout js component as a demonstrated when creating a check/uncheck all one. The following JavaScript code should be placed (or included from a separate file) after the Knockout framework is included, but before your ViewModel is defined and the Knockout bindings are applied.


<script>
ko.bindingHandlers.radioButtonGroup = {
init: function (element, valueAccessor, allBindings, viewModel, context) {
var $buttons, $element, observable;
observable = valueAccessor();
if (!ko.isWriteableObservable(observable)) {
throw "You must pass an observable or writeable computed";
}
$element = $(element);
if ($element.hasClass("btn")) {
$buttons = $element;
} else {
$buttons = $(".btn", $element);
}
elementBindings = allBindings();
$buttons.each(function () {
var $btn, btn, radioValue;
btn = this;
$btn = $(btn);
radioValue = elementBindings.radioValue || $btn.attr("data-value") || $btn.attr("value") || $btn.text();
$btn.on("click", function () {
observable(ko.utils.unwrapObservable(radioValue));
});
return ko.computed({
disposeWhenNodeIsRemoved: btn,
read: function () {
$btn.toggleClass("active", observable() === ko.utils.unwrapObservable(radioValue));
$btn.toggleClass("btn-info", observable() === ko.utils.unwrapObservable(radioValue));
}
});
});
}
};
</script>

The init function accepts 5 parameters. The element being data bound, the variable it is data bound too, all other bindings on this element, the entire ViewModel (however this is being deprecated), and the bindingContext, this is the new way proposed to access the ViewModel by using bindingContext.$data.

Inside the init function, it first verifies it is dealing with an observable property. Using the HTML element with the data binding (and some jQuery), the related buttons are found and stored in a variable. These buttons are then looped through and the click event is listened for. When it occurs, the observable property associated to the data binding's value is updated with the option selected. And finally a computed variable is defined, that if the observable's value is equal the value of the button, the class active and btn-info are added to identify which button is currently selected.

For readability the example has been broken into small chunks, the full source code is available on GitHub - Knockout js Examples

Published on Apr 27, 2015

Tags: Knockout js Tutorial | observable | Bootstrap | radio buttons

Related Posts

Did you enjoy this article? If you did here are some more articles that I thought you will enjoy as they are very similar to the article that you just finished reading.

Tutorials

Learn how to code in HTML, CSS, JavaScript, Python, Ruby, PHP, Java, C#, SQL, and more.

No matter the programming language you're looking to learn, I've hopefully compiled an incredible set of tutorials for you to learn; whether you are beginner or an expert, there is something for everyone to learn. Each topic I go in-depth and provide many examples throughout. I can't wait for you to dig in and improve your skillset with any of the tutorials below.