steveluscher / knockout.meteor

A Knockout-to-Meteor bridge
http://steveluscher.github.com/knockout.meteor
MIT License
66 stars 10 forks source link

Knockout Meteor

Creates Knockout Observables based on queries against Meteor Collections. When the results of those queries change, Knockout Meteor will ensure that the associated Observables are updated.

Why?

Knockout lets you create complex associations between Javascript model data and DOM elements using an expressive and declarative binding syntax. The Knockout Mapping plugin excels at atomically updating your Javascript models (and hence your UI) based on incoming data, updating only that which has changed. These are two strengths that Meteor does not currently possess.

Meteor, however, makes it incredibly easy to ferry model data back and forth between a server and its connected clients. Knockout Meteor acts as a bridge between these two frameworks. It lets you construct queries against Meteor Collections that behave like Knockout Observables that update themselves atomically and automatically when the results of those queries change.

Usage

Let's assume there exists a Meteor.Collection called Todos, and that our view model wants to track unfinished todos, finished todos, and the oldest unfinished todo.

var Todos = new Meteor.Collection("todos");

In the view model:

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); } );

In the HTML:

Since ko.meteor.find() and ko.meteor.findOne() return instances of ko.observableArray and ko.observable respectively, you can bind to them in the way you're used to:

<ul data-bind="foreach: unfinishedTodos">
  <li data-bind="text: title"></li>
</ul>

Any update to the Meteor Todos collection will now trigger a UI refresh. This includes local updates, and updates pushed from the server.

Documentation

ko.meteor.find() and ko.meteor.findOne() share the same method signature.

ko.meteor.find( collection, selector[, options, mapping] )
ko.meteor.findOne( collection, selector[, options, mapping] )

The collection argument

Must be an instance of a Meteor.Collection, or an Observable that wraps an instance of a Meteor.Collection.

The selector argument

A Mongo selector, a String, or an Observable that wraps a Mongo selector or String. See the Meteor documentation on find() or findOne() for more information.

The options argument

(Optional) An Object, or an Observable that wraps an Object. See the Meteor documentation on the options argument of find() and findOne() for more information.

The mapping argument

(Optional) An Object, or an Observable that wraps an Object. Recognizes the following special property:

The mapper will instantiate an object using this constructor, then map each record in the Meteor Collection to the resulting instance. The constructor will receive, as its first parameter, an object representing the data returned from the query.

The remaining mapping properties will be passed through to the Knockout Mapping plugin. See the "Advanced Usage" section of the Knockout Mapping documentation for more information.

Requirements

Developing

Want to contribute? Great! To hack away you'll want a clone of this repo, and the Coffeescript compiler.

> git clone https://github.com/steveluscher/knockout.meteor.git
> cd knockout.meteor
> npm install

make compile will compile the Coffeescript file in ./src into Javascript files located in ./build and ./example/client. Use make watch if you would like the compiler to run every time you save.

Giving thanks

Web development pays bills, but my real passion is music. If you found this code useful, the best way to say thank you is to support my band Lakefield (@lakefieldmusic).

License

Copyright (C) 2012-2013 Steven Luscher (@steveluscher) and Ruboss Technology Coporation (@rubosstech) – Released under the MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.