A JavaScript library that helps you create rich, maintainable, and responsive user interfaces. Changes made to observed objects are reflected back to other objects that depend on them. The declarative bindings help to eliminate jQuery spaghetti!
Some key features
The Model View ViewModel pattern is used to facilitate a clear separation of the graphical user interface (ie. markup) from the development of the business logic or back end logic known as the data model.
Model: a data access layer that contains the content
View: the markup necessary to display content, controls, etc
View model: an abstraction of the view that serves in mediating between the view and the model. Exposes public properties and commands. Passes commands from the view to the model.
Read the Wikipedia article for more information! Too much to cover here.
var personModel = {
name: ko.observable('Adam'), // Initialized with a value
favouriteDrink: ko.observable(),
};
// Get value
personModel.name();
// Set value
personModel.favouriteDrink('Beer');
// Define our viewModel
var viewModel = {
// Create our fruits property with two fruits pre-defined
fruits: ko.observableArray(["Apples", "Pears"]);
};
// Append another fruit to fruits
viewModel.fruits.push("Bananas");
// Give me some Apples
viewModel.fruits.shift();
A simple and obvious way to connect parts of your UI to your data model.
<span data-bind="text: firstName"></span>
<input data-bind="value: firstName">
<select data-bind="options: availableCountries, value: birthCountry"></select>
<div data-bind="visible: hasName">
I am visible when hasName evaluates true
</div>
<span data-bind="css: { inStock: stockLevel() > 0 }"></span>
<ul data-bind="foreach: people">
<li data-bind="text: firstName"></li>
</ul>
...and many more!
Automatic synchronization of data between the model and view components
var viewModel = {
firstName: ko.observable("Adam"),
};
ko.applyBindings(viewModel);
<input data-bind="value: firstName, valueUpdate: 'keyup'">
<span data-bind="text: firstName"></span>
Intialized by <!-- ko binding: argument --> and closed by <!-- /ko -->
Useful if you don't need a parent HTML element
<!-- ko foreach: pages -->
<!-- ko if: $root.page() == $data -->
<em class="current" data-bind="text: $data"></em>
<!-- /ko -->
<!-- ko ifnot: $root.page() == $data -->
<a data-bind="text: $data, click: $root.page"></a>
<!-- /ko -->
<!-- /ko -->
Functions that automatically update when their dependencies change.
this.fullName = ko.computed(function() {
return this.firstName() + " " + this.lastName();
}, this);
ko.computed(function() {
var params = { page: this.currentPage() }; // Our dependency(s)
uri.fragment(params); // uri is provided by URI.js
window.location = uri.toString();
}, this);
ko.computed(function() {
$.getJSON(window.location.href, { category: this.category() });
}, this).extend({ throttle: 500 });
function viewModel() {
this.movies = ["Back to the Future", "Ghostbusters", "Caddyshack", "The Phantom"];
this.filter = ko.observable(""),
this.filteredMovies = ko.computed(function () {
var filter = this.filter().toLowerCase();
if (!filter) {
return this.movies;
} else {
return ko.utils.arrayFilter(this.movies, function (movie) {
return movie.toLowerCase().indexOf(filter) !== -1;
});
}
}, this);
};
ko.applyBindings(new viewModel());
<input data-bind="value: filter, valueUpdate: 'keyup'">
<ul data-bind="foreach: filteredMovies">
<li data-bind="text: $data"></li>
<ul>
function viewModel() {
this.movies = ["Back to the Future", "Ghostbusters", "Caddyshack", "The Phantom"];
this.filter = ko.observable(""),
this.filteredMovies = ko.computed(function () {
var filter = this.filter().toLowerCase();
if (!filter) {
return this.movies;
} else {
return ko.utils.arrayFilter(this.movies, function (movie) {
return movie.toLowerCase().indexOf(filter) !== -1;
});
}
}, this);
};
ko.applyBindings(new viewModel());
<input data-bind="value: filter, valueUpdate: 'keyup'">
<ul data-bind="foreach: filteredMovies">
<li data-bind="text: $data"></li>
<ul>
function Task(title) {
this.title = ko.observable(title);
this.completed = ko.observable(false);
this.toggleCompleted = function() {
this.completed(! this.completed());
};
};
function ViewModel() {
this.tasks = ko.observableArray();
this.currentTask = ko.observable();
this.addTask = function() {
this.tasks.push(new Task(this.currentTask()))
this.currentTask("");
}.bind(this);
this.tasks.push(new Task("Drink beer"));
this.tasks.push(new Task("Write code"));
};
ko.applyBindings(new ViewModel());
<ul data-bind="foreach: tasks">
<li data-bind="text: title, click: toggleCompleted, css: { completed: completed }"></li>
</ul>
<form data-bind="submit: addTask">
<input data-bind="value: currentTask">
</form>
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
cursor: pointer;
margin: 0.5em 0.5em 0.5em 0;
}
.completed {
text-decoration: line-through;
opacity: 0.8;
}
function Task(title) {
this.title = ko.observable(title);
this.completed = ko.observable(false);
this.toggleCompleted = function() {
this.completed(! this.completed());
};
};
function ViewModel() {
this.tasks = ko.observableArray();
this.currentTask = ko.observable();
this.addTask = function() {
this.tasks.push(new Task(this.currentTask()))
this.currentTask("");
}.bind(this);
this.tasks.push(new Task("Drink beer"));
this.tasks.push(new Task("Write code"));
};
ko.applyBindings(new ViewModel());
<ul data-bind="foreach: tasks">
<li data-bind="text: title, click: toggleCompleted, css: { completed: completed }"></li>
</ul>
<form data-bind="submit: addTask">
<input data-bind="value: currentTask">
</form>
/