<!-- ko if:myObservable --><!-- /ko -->
<i data-bind="if:myObservable"></i>
Essentially a binding or a data binding is a way to link your ViewModels to your Views(templates) and vice versa. KnockoutJS uses two-way data binding, which means changes to your ViewModel influence the View and changes to your View can influence the ViewModel.
Bindings are just plugins (scripts) that allow you to solve a particular task. This task is more often than not is changing markup (html) according to your ViewModel.
For example, a text
binding allows you to display text and dynamically change it whenever your ViewModel changes.
KnockoutJS comes with many powerful bindings and lets you extend it with your own custom bindings.
And most importantly bindings are not magical, they work according to a set of rules and anytime you are unsure of what a binding does, what parameters it takes or when it will update the view you can refer to source code of the binding.
Consider the following example of a custom binding:
ko.bindingHandlers.debug = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
ko.computed(function () {
var value = ko.unwrap(valueAccessor());
console.log({
value: value,
viewModel: viewModel,
bindingContext: bindingContext
});
}, null, { disposeWhenNodeIsRemoved: element });
}
};
debug
so you can use as follows:data-bind="debug: 'foo'"
init
method is called once when the binding is initiated. The rest of the updates are handled by a anonymous computed which is disposed when element
is removed.foo
(this value can also be observable since ko.unwrap
method is used to read it), the current viewModel and bindingContext.ko.virtualElements.allowedBindings.debug
flag is not set to true.Without any additional plugins, KnockoutJS will only have live View updates for properties on the ViewModel that are observable (regular observable
, but also computed
, pureComputed
, observableArray
, etc). An observable would be created like this:
var vm = { name: ko.observable("John") };
In this case, vm.name
is a function with two seperate "modes":
vm.name()
, without arguments, will get the current value;vm.name("Johnnyboy")
, with an argument, will set a new value.In the built-in data-bindings you can always use the getter form, and you can sometimes actually omit the parentheses, and the binding will effectively "add" them for you. So these are equivalent:
<p data-bind="text: name"></p> ... will work
<p data-bind="text: name()"></p> ... works too
But this will fail:
<p data-bind="text: 'Hello, ' + name + '!'"></p> ... FAILS!
Because as soon as you want to "do" something before passing a value to a data-binding, including value comparisons, you need to properly "get" the values for all observables, e.g.:
<p data-bind="text: 'Hello, ' + name() + '!'"></p> ... works
See also this Q&A for more details.