Knockout.js provides powerful data-binding capabilities that allow you to create dynamic, responsive web applications. Beyond the basics of binding HTML elements to observables, there are several advanced techniques you can use to handle more complex scenarios. This guide will cover some of these advanced data-binding techniques, including computed observables, custom bindings, and working with complex data structures.
Computed Observables
Computed observables are functions that are dependent on one or more other observables. They automatically update when any of the underlying observables change.
<!doctype html>
<html lang="en">
<head>
<!-- Meta tags for character set and viewport configuration -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Title of the webpage -->
<title>Bootstrap demo</title>
<!-- Link to Bootstrap CSS for styling -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<!-- Link to Knockout.js library for MVVM pattern support -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.1/knockout-latest.min.js"
integrity="sha512-vs7+jbztHoMto5Yd/yinM4/y2DOkPLt0fATcN+j+G4ANY2z4faIzZIOMkpBmWdcxt+596FemCh9M18NUJTZwvw=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body class="container">
<div>
<label>First Name: <input data-bind="value: firstName" /></label>
<label>Last Name: <input data-bind="value: lastName" /></label>
<h2>Hello, <span data-bind="text: fullName"></span>!</h2>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.1/knockout-latest.min.js"></script>
<script>
function AppViewModel() {
var self = this;
self.firstName = ko.observable('John');
self.lastName = ko.observable('Doe');
self.fullName = ko.computed(function () {
return self.firstName() + ' ' + self.lastName();
});
}
ko.applyBindings(new AppViewModel());
</script>
</body>
</html>
In this example, fullName
is a computed observable that combines
firstName
and lastName
. It updates automatically whenever
firstName
or lastName
changes.
Custom Bindings
Custom bindings allow you to create bindings that can encapsulate complex behavior or integrate with third-party libraries.
Example
Let's create a custom binding to integrate with the jQuery UI Datepicker.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Custom Binding Example</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
</head>
<body class="container">
<div>
<label>Select Date: <input data-bind="datepicker: selectedDate" /></label>
<h2>Selected Date: <span data-bind="text: selectedDate"></span></h2>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.1/knockout-latest.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<script>
ko.bindingHandlers.datepicker = {
init: function(element, valueAccessor, allBindingsAccessor) {
var options = allBindingsAccessor().datepickerOptions || {};
$(element).datepicker(options);
ko.utils.registerEventHandler(element, "change", function() {
var observable = valueAccessor();
observable($(element).val());
});
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
$(element).datepicker("destroy");
});
},
update: function(element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
$(element).datepicker("setDate", value);
}
};
function AppViewModel() {
var self = this;
self.selectedDate = ko.observable();
}
ko.applyBindings(new AppViewModel());
</script>
</body>
</html>
In this example, the custom binding datepicker
integrates the jQuery UI Datepicker with a Knockout observable. When the date is changed in the date picker, the observable
selectedDate
is updated.
Using Knockout with AJAX
Knockout.js can be used with AJAX calls to fetch and update data from a server. This is useful for building applications that need to interact with a backend service.
<script>
function AppViewModel() {
var self = this;
self.products = ko.observableArray([]);
// Function to load products from a server
self.loadProducts = function () {
$.getJSON('/api/products', function (data) {
var mappedProducts = data.map(function (item) {
return {
name: ko.observable(item.name),
price: ko.observable(item.price)
};
});
self.products(mappedProducts);
});
};
}
// Apply Knockout.js bindings to the AppViewModel
ko.applyBindings(new AppViewModel());
</script>
Working with Complex Data Structures
Knockout.js makes it easy to work with complex data structures using nested observables and observable arrays.
<script>
function AppViewModel() {
var self = this;
// Observables for new product input fields
self.newProductName = ko.observable('');
self.newProductPrice = ko.observable('');
// Observable array to store the list of products
self.products = ko.observableArray([]);
// Function to add a new product to the list
self.addProduct = function () {
self.products.push({
name: ko.observable(self.newProductName()),
price: ko.observable(self.newProductPrice()),
variants: ko.observableArray([
{ variantName: ko.observable('Variant 1'), variantPrice: ko.observable(10) },
{ variantName: ko.observable('Variant 2'), variantPrice: ko.observable(20) }
])
});
self.newProductName('');
self.newProductPrice('');
};
// Function to start editing a product
self.editProduct = function (product) {
// Logic to edit product
};
// Function to save changes to the edited product
self.saveProduct = function () {
// Logic to save edited product
};
// Function to delete a product from the list
self.deleteProduct = function (product) {
self.products.remove(product);
};
}
// Apply Knockout.js bindings to the AppViewModel
ko.applyBindings(new AppViewModel());
</script>
Read more
Retrieve Data from RESTFul API and add Paging
Form validation and request submission in knockout js
Knockout.js: Building Dynamic Web Applications
Leave Comment