Knockout is a JavaScript MVVM (a modern variant of MVC) library that makes it easier to create rich, desktop-like user interfaces with JavaScript and HTML. It uses observers to make your UI automatically stay in sync with an underlying data model, along with a powerful and extensible set of declarative bindings to enable productive development.
Meteor makes it an order of magnitude simpler and a lot more fun to build webapps. However, we still want to have a MV* frontend framework in Meteor. Handlebar uses '{{}}', which is conflict with frameworks like AngularJs and EmberJs. So 'data-bind' like frameworks (e.g. Knockout) play nicely with Meteor.
knockout-client
is fully compatible and ready to use. Please note, this version is hosted on atmosphere as knockout-client
simply because the orignal meteor-knockout
has not been update for some time.
meteor add mrt:knockout-client
This package exposes ko
to the global namespace. Compatible with Meteor 0.6.4.1
and 0.6.5
.
knockout-client
includes some useful plugins:
ko
-- knockout base, see its doc.ko.mapping
-- knockout mapping, see its doc.ko.meteor
-- knockout meteor bridge. Thanks to steveluscher/knockout.meteor. It expose two apis:
ko.meteor.find
ko.meteor.findOne
ko.validation
-- knockout validation plugin. Thanks to ericmbarnard/Knockout-Validation.
If you are looking for a knockout based routing framework, please consider package knockout-client-pager
. see [zhouzhuojie/knockout-client-pager]()
In client side:
Meteor.startup(function(){
// Here's my data model
var ViewModel = function(first, last) {
this.firstName = ko.observable(first);
this.lastName = ko.observable(last);
this.fullName = ko.computed(function() {
// Knockout tracks dependencies automatically. It knows that fullName depends on firstName and lastName, because these get called when evaluating fullName.
return this.firstName() + " " + this.lastName();
}, this);
};
ko.applyBindings(new ViewModel("Planet", "Earth")); // This makes Knockout get to work
});
In html template:
<template name="foo">
<p>First name: <input data-bind="value: firstName" /></p>
<p>Last name: <input data-bind="value: lastName" /></p>
<h2>Hello, <span data-bind="text: fullName"> </span>!</h2>
</template>
Other data-bind
attributes please refer to the great document of Knockout.
Sometimes you may want to prevent it from reactive template refreshing, because reactive refresh will leave the data-bind unattached.
so you can either
{{#constant}}...{{/constant}}
, like<template name="foo">
{{#constant}}
<p>First name: <input data-bind="value: firstName" /></p>
<p>Last name: <input data-bind="value: lastName" /></p>
<h2>Hello, <span data-bind="text: fullName"> </span>!</h2>
{{/constant}}
</template>
or
ko.applyBindings(...)
in Template.foo.rendered = function(){...}
, likeTemplate.foo.rendered = function(){
// Here's my data model
var ViewModel = function(first, last) {
this.firstName = ko.observable(first);
this.lastName = ko.observable(last);
this.fullName = ko.computed(function() {
// Knockout tracks dependencies automatically. It knows that fullName depends on firstName and lastName, because these get called when evaluating fullName.
return this.firstName() + " " + this.lastName();
}, this);
};
ko.applyBindings(new ViewModel("Planet", "Earth")); // This makes Knockout get to work
};
Use ko.meteor.find()
and ko.meteor.findOne()
like you would normally use ko.observableArray()
and ko.observable()
:
var viewModel = {
unfinishedTodos: ko.meteor.find(Todos, {done: false}),
finishedTodos: ko.meteor.find(Todos, {done: true}),
oldestUnfinishedTodo: ko.meteor.findOne(Todos, {done: true}, {sort: {created_at:1}})
};
Meteor.startup( function() { ko.applyBindings(viewModel); } );
For multiple cursor like ko.meteor.find()
, use data-bind="foreach: foobar"
.
<ul data-bind="foreach: unfinishedTodos">
<li data-bind="text: title"></li>
</ul>
For single cursor like ko.meteor.findOne()
, you can still use data-bind="foreach: foobar"
<ul data-bind="foreach: oldestUnfinishedTodo">
<li data-bind="text: title"></li>
</ul>
or data-bind="with: foobar"
<ul data-bind="with: oldestUnfinishedTodo">
<li data-bind="text: title"></li>
</ul>
or knockout's context definition <!-- ko with: foobar --> ... <!-- /ko -->
<!-- ko with: oldestUnfinishedTodo -->
<p data-bind="text: title"></p>
<!-- /ko -->
For more information, see steveluscher/knockout.meteor.
Before you get started with ko.validation
, you need to configure it.
Meteor.startup(function(){
ko.validation.configure({
registerExtenders: true,
messgaesOnModified: true
});
});
and then define your rules into ko observables with .extend(...)
.
var ViewModel = function(first, last) {
this.firstName = ko.observable(first).extend({ minLength: 3 });
this.lastName = ko.observable(last).extend({ required: true });
};
For more information, see ericmbarnard/Knockout-Validation.