Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
  • 2 commits
  • 8 files changed
  • 0 commit comments
  • 1 contributor
Commits on Jul 19, 2012
@steveluscher We got the method signature wrong the first time around. Meteor optio…
…ns and Knockout Mapping options are now separate arguments to find() and findOne().
62ebc44
@steveluscher :punch: Bumping version to 0.3; breaking changes in the method signatures o…
…f find() and findOne().
c997493
View
20 README.md
@@ -21,7 +21,7 @@ Use `ko.meteor.find()` and `ko.meteor.findOne()` like you would normally use `ko
var viewModel = {
unfinishedTodos: ko.meteor.find(Todos, {done: false}),
finishedTodos: ko.meteor.find(Todos, {done: true}),
- oldestUnfinishedTodo: ko.meteor.findOne(Todos, {done: true}, {meteor_options: {sort: {created_at:1}}})
+ oldestUnfinishedTodo: ko.meteor.findOne(Todos, {done: true}, {sort: {created_at:1}})
};
Meteor.startup( function() { ko.applyBindings(viewModel); } );
@@ -39,8 +39,8 @@ Any update to the Meteor `Todos` collection will now trigger a UI refresh. This
`ko.meteor.find()` and `ko.meteor.findOne()` share the same method signature.
- ko.meteor.find( collection, selector[, options] )
- ko.meteor.findOne( collection, selector[, options] )
+ ko.meteor.find( collection, selector[, options, mapping] )
+ ko.meteor.findOne( collection, selector[, options, mapping] )
### The `collection` argument ###
@@ -52,19 +52,17 @@ A Mongo selector, a String, or an `Observable` that wraps a Mongo selector or St
### The `options` argument ###
-(Optional) An Object, or an `Observable` that wraps an Object. Recognizes the following keys:
+(Optional) An Object, or an `Observable` that wraps an Object. See the Meteor documentation on the `options` argument of [`find()`](http://docs.meteor.com/#find) and [`findOne()`](http://docs.meteor.com/#findone) for more information.
-* `view_model` – an object constructor.
+### The `mapping` argument ###
-> 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.
+(Optional) An Object, or an `Observable` that wraps an Object. Recognizes the following special property:
-* `meteor_options`additional configuration for `Meteor.Collection.find()` or `Meteor.Collection.findOne()`.
+* `view_model`an object constructor.
-> See the Meteor documentation on the `options` argument of [`find()`](http://docs.meteor.com/#find) and [`findOne()`](http://docs.meteor.com/#findone) for more information.
-
-* `mapping` – additional configuration for the Knockout Mapping plugin.
+> 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.
-> See the "[Advanced Usage](http://knockoutjs.com/documentation/plugins-mapping.html#advanced_usage)" section of the Knockout Mapping documentation for more information.
+The remaining `mapping` properties will be passed through to the Knockout Mapping plugin. See the "[Advanced Usage](http://knockoutjs.com/documentation/plugins-mapping.html#advanced_usage)" section of the Knockout Mapping documentation for more information.
## Requirements ##
View
63 build/knockout.meteor.js
@@ -33,27 +33,34 @@ http://github.com/steveluscher/knockout.meteor
})(Error);
meteor = {
- find: function(collection, selector, options) {
+ find: function(collection, selector, options, mapping) {
if (options == null) {
options = {};
}
- return (new FindMany(collection, selector, options)).run();
+ if (mapping == null) {
+ mapping = {};
+ }
+ return (new FindMany(collection, selector, options, mapping)).run();
},
- findOne: function(collection, selector, options) {
+ findOne: function(collection, selector, options, mapping) {
if (options == null) {
options = {};
}
- return (new FindOne(collection, selector, options)).run();
+ if (mapping == null) {
+ mapping = {};
+ }
+ return (new FindOne(collection, selector, options, mapping)).run();
}
};
AbstractFinder = (function() {
- function AbstractFinder(collection, selector, options) {
+ function AbstractFinder(collection, selector, options, mapping) {
var _this = this;
this.collection = collection;
this.selector = selector;
this.options = options != null ? options : {};
+ this.mapping = mapping != null ? mapping : {};
this.run = __bind(this.run, this);
this.target = null;
@@ -61,50 +68,50 @@ http://github.com/steveluscher/knockout.meteor
ko.utils.unwrapObservable(_this.collection);
ko.utils.unwrapObservable(_this.selector);
ko.utils.unwrapObservable(_this.options);
+ ko.utils.unwrapObservable(_this.mapping);
}).extend({
throttle: 1
}).subscribe(this.run);
}
AbstractFinder.prototype.run = function() {
- var collection, options, selector;
+ var collection, mapping, options, selector;
if (this.query) {
this.query.destroy();
}
collection = ko.utils.unwrapObservable(this.collection);
selector = ko.utils.unwrapObservable(this.selector);
options = ko.utils.unwrapObservable(this.options);
- this.applyDefaults(options);
- this.query = this.createQuery(collection, selector, options);
+ mapping = this.processMapping(ko.utils.unwrapObservable(this.mapping));
+ this.query = this.createQuery(collection, selector, options, mapping);
return this.query.run();
};
- AbstractFinder.prototype.applyDefaults = function(options) {
- _.defaults(options, {
- mapping: {},
- view_model: null
- });
- if (!_.isObject(options.mapping[""])) {
- options.mapping[""] = {};
+ AbstractFinder.prototype.processMapping = function(raw_mapping) {
+ var mapping, view_model;
+ mapping = _.clone(raw_mapping);
+ view_model = mapping.view_model;
+ delete mapping.view_model;
+ if (!_.isObject(mapping[""])) {
+ mapping[""] = {};
}
- _.defaults(options.mapping[""], {
+ _.defaults(mapping[""], {
key: function(item) {
return ko.utils.unwrapObservable(item._id);
}
});
- if (_.isFunction(options.view_model)) {
- return options.mapping[""].create = function(opts) {
- var view_model;
+ if (_.isFunction(view_model)) {
+ mapping[""].create = function(opts) {
if (!opts.data) {
return ko.observable();
}
- view_model = new options.view_model(opts.data);
- return ko.mapping.fromJS(opts.data, options.mapping, view_model);
+ return ko.mapping.fromJS(opts.data, mapping, new view_model(opts.data));
};
}
+ return mapping;
};
- AbstractFinder.prototype.createQuery = function(collection, selector, options) {
+ AbstractFinder.prototype.createQuery = function(collection, selector, options, mapping) {
throw new NotImplementedError('createQuery');
};
@@ -120,14 +127,14 @@ http://github.com/steveluscher/knockout.meteor
return FindMany.__super__.constructor.apply(this, arguments);
}
- FindMany.prototype.createQuery = function(collection, selector, options) {
+ FindMany.prototype.createQuery = function(collection, selector, options, mapping) {
var data_func, meteor_cursor;
- meteor_cursor = collection.find(selector, options.meteor_options);
+ meteor_cursor = collection.find(selector, options);
data_func = function() {
meteor_cursor.rewind();
return meteor_cursor.fetch();
};
- return new MappedQuery(this, data_func, options.mapping);
+ return new MappedQuery(this, data_func, mapping);
};
return FindMany;
@@ -142,12 +149,12 @@ http://github.com/steveluscher/knockout.meteor
return FindOne.__super__.constructor.apply(this, arguments);
}
- FindOne.prototype.createQuery = function(collection, selector, options) {
+ FindOne.prototype.createQuery = function(collection, selector, options, mapping) {
var data_func;
data_func = function() {
- return collection.findOne(selector, options.meteor_options);
+ return collection.findOne(selector, options);
};
- return new MappedQuery(this, data_func, options.mapping);
+ return new MappedQuery(this, data_func, mapping);
};
return FindOne;
View
63 examples/dynamic_finders/client/knockout.meteor.js
@@ -33,27 +33,34 @@ http://github.com/steveluscher/knockout.meteor
})(Error);
meteor = {
- find: function(collection, selector, options) {
+ find: function(collection, selector, options, mapping) {
if (options == null) {
options = {};
}
- return (new FindMany(collection, selector, options)).run();
+ if (mapping == null) {
+ mapping = {};
+ }
+ return (new FindMany(collection, selector, options, mapping)).run();
},
- findOne: function(collection, selector, options) {
+ findOne: function(collection, selector, options, mapping) {
if (options == null) {
options = {};
}
- return (new FindOne(collection, selector, options)).run();
+ if (mapping == null) {
+ mapping = {};
+ }
+ return (new FindOne(collection, selector, options, mapping)).run();
}
};
AbstractFinder = (function() {
- function AbstractFinder(collection, selector, options) {
+ function AbstractFinder(collection, selector, options, mapping) {
var _this = this;
this.collection = collection;
this.selector = selector;
this.options = options != null ? options : {};
+ this.mapping = mapping != null ? mapping : {};
this.run = __bind(this.run, this);
this.target = null;
@@ -61,50 +68,50 @@ http://github.com/steveluscher/knockout.meteor
ko.utils.unwrapObservable(_this.collection);
ko.utils.unwrapObservable(_this.selector);
ko.utils.unwrapObservable(_this.options);
+ ko.utils.unwrapObservable(_this.mapping);
}).extend({
throttle: 1
}).subscribe(this.run);
}
AbstractFinder.prototype.run = function() {
- var collection, options, selector;
+ var collection, mapping, options, selector;
if (this.query) {
this.query.destroy();
}
collection = ko.utils.unwrapObservable(this.collection);
selector = ko.utils.unwrapObservable(this.selector);
options = ko.utils.unwrapObservable(this.options);
- this.applyDefaults(options);
- this.query = this.createQuery(collection, selector, options);
+ mapping = this.processMapping(ko.utils.unwrapObservable(this.mapping));
+ this.query = this.createQuery(collection, selector, options, mapping);
return this.query.run();
};
- AbstractFinder.prototype.applyDefaults = function(options) {
- _.defaults(options, {
- mapping: {},
- view_model: null
- });
- if (!_.isObject(options.mapping[""])) {
- options.mapping[""] = {};
+ AbstractFinder.prototype.processMapping = function(raw_mapping) {
+ var mapping, view_model;
+ mapping = _.clone(raw_mapping);
+ view_model = mapping.view_model;
+ delete mapping.view_model;
+ if (!_.isObject(mapping[""])) {
+ mapping[""] = {};
}
- _.defaults(options.mapping[""], {
+ _.defaults(mapping[""], {
key: function(item) {
return ko.utils.unwrapObservable(item._id);
}
});
- if (_.isFunction(options.view_model)) {
- return options.mapping[""].create = function(opts) {
- var view_model;
+ if (_.isFunction(view_model)) {
+ mapping[""].create = function(opts) {
if (!opts.data) {
return ko.observable();
}
- view_model = new options.view_model(opts.data);
- return ko.mapping.fromJS(opts.data, options.mapping, view_model);
+ return ko.mapping.fromJS(opts.data, mapping, new view_model(opts.data));
};
}
+ return mapping;
};
- AbstractFinder.prototype.createQuery = function(collection, selector, options) {
+ AbstractFinder.prototype.createQuery = function(collection, selector, options, mapping) {
throw new NotImplementedError('createQuery');
};
@@ -120,14 +127,14 @@ http://github.com/steveluscher/knockout.meteor
return FindMany.__super__.constructor.apply(this, arguments);
}
- FindMany.prototype.createQuery = function(collection, selector, options) {
+ FindMany.prototype.createQuery = function(collection, selector, options, mapping) {
var data_func, meteor_cursor;
- meteor_cursor = collection.find(selector, options.meteor_options);
+ meteor_cursor = collection.find(selector, options);
data_func = function() {
meteor_cursor.rewind();
return meteor_cursor.fetch();
};
- return new MappedQuery(this, data_func, options.mapping);
+ return new MappedQuery(this, data_func, mapping);
};
return FindMany;
@@ -142,12 +149,12 @@ http://github.com/steveluscher/knockout.meteor
return FindOne.__super__.constructor.apply(this, arguments);
}
- FindOne.prototype.createQuery = function(collection, selector, options) {
+ FindOne.prototype.createQuery = function(collection, selector, options, mapping) {
var data_func;
data_func = function() {
- return collection.findOne(selector, options.meteor_options);
+ return collection.findOne(selector, options);
};
- return new MappedQuery(this, data_func, options.mapping);
+ return new MappedQuery(this, data_func, mapping);
};
return FindOne;
View
6 examples/dynamic_finders/example.js
@@ -17,9 +17,9 @@ if (Meteor.is_client) {
});
var options = ko.computed(function() {
- var meteor_options = { sort: {} };
- meteor_options.sort[sortField().toLowerCase()] = sortAsc() ? 1 : -1;
- return { meteor_options: meteor_options };
+ var options = { sort: {} };
+ options.sort[sortField().toLowerCase()] = sortAsc() ? 1 : -1;
+ return options;
});
// finders!
View
63 examples/todo_list/client/knockout.meteor.js
@@ -33,27 +33,34 @@ http://github.com/steveluscher/knockout.meteor
})(Error);
meteor = {
- find: function(collection, selector, options) {
+ find: function(collection, selector, options, mapping) {
if (options == null) {
options = {};
}
- return (new FindMany(collection, selector, options)).run();
+ if (mapping == null) {
+ mapping = {};
+ }
+ return (new FindMany(collection, selector, options, mapping)).run();
},
- findOne: function(collection, selector, options) {
+ findOne: function(collection, selector, options, mapping) {
if (options == null) {
options = {};
}
- return (new FindOne(collection, selector, options)).run();
+ if (mapping == null) {
+ mapping = {};
+ }
+ return (new FindOne(collection, selector, options, mapping)).run();
}
};
AbstractFinder = (function() {
- function AbstractFinder(collection, selector, options) {
+ function AbstractFinder(collection, selector, options, mapping) {
var _this = this;
this.collection = collection;
this.selector = selector;
this.options = options != null ? options : {};
+ this.mapping = mapping != null ? mapping : {};
this.run = __bind(this.run, this);
this.target = null;
@@ -61,50 +68,50 @@ http://github.com/steveluscher/knockout.meteor
ko.utils.unwrapObservable(_this.collection);
ko.utils.unwrapObservable(_this.selector);
ko.utils.unwrapObservable(_this.options);
+ ko.utils.unwrapObservable(_this.mapping);
}).extend({
throttle: 1
}).subscribe(this.run);
}
AbstractFinder.prototype.run = function() {
- var collection, options, selector;
+ var collection, mapping, options, selector;
if (this.query) {
this.query.destroy();
}
collection = ko.utils.unwrapObservable(this.collection);
selector = ko.utils.unwrapObservable(this.selector);
options = ko.utils.unwrapObservable(this.options);
- this.applyDefaults(options);
- this.query = this.createQuery(collection, selector, options);
+ mapping = this.processMapping(ko.utils.unwrapObservable(this.mapping));
+ this.query = this.createQuery(collection, selector, options, mapping);
return this.query.run();
};
- AbstractFinder.prototype.applyDefaults = function(options) {
- _.defaults(options, {
- mapping: {},
- view_model: null
- });
- if (!_.isObject(options.mapping[""])) {
- options.mapping[""] = {};
+ AbstractFinder.prototype.processMapping = function(raw_mapping) {
+ var mapping, view_model;
+ mapping = _.clone(raw_mapping);
+ view_model = mapping.view_model;
+ delete mapping.view_model;
+ if (!_.isObject(mapping[""])) {
+ mapping[""] = {};
}
- _.defaults(options.mapping[""], {
+ _.defaults(mapping[""], {
key: function(item) {
return ko.utils.unwrapObservable(item._id);
}
});
- if (_.isFunction(options.view_model)) {
- return options.mapping[""].create = function(opts) {
- var view_model;
+ if (_.isFunction(view_model)) {
+ mapping[""].create = function(opts) {
if (!opts.data) {
return ko.observable();
}
- view_model = new options.view_model(opts.data);
- return ko.mapping.fromJS(opts.data, options.mapping, view_model);
+ return ko.mapping.fromJS(opts.data, mapping, new view_model(opts.data));
};
}
+ return mapping;
};
- AbstractFinder.prototype.createQuery = function(collection, selector, options) {
+ AbstractFinder.prototype.createQuery = function(collection, selector, options, mapping) {
throw new NotImplementedError('createQuery');
};
@@ -120,14 +127,14 @@ http://github.com/steveluscher/knockout.meteor
return FindMany.__super__.constructor.apply(this, arguments);
}
- FindMany.prototype.createQuery = function(collection, selector, options) {
+ FindMany.prototype.createQuery = function(collection, selector, options, mapping) {
var data_func, meteor_cursor;
- meteor_cursor = collection.find(selector, options.meteor_options);
+ meteor_cursor = collection.find(selector, options);
data_func = function() {
meteor_cursor.rewind();
return meteor_cursor.fetch();
};
- return new MappedQuery(this, data_func, options.mapping);
+ return new MappedQuery(this, data_func, mapping);
};
return FindMany;
@@ -142,12 +149,12 @@ http://github.com/steveluscher/knockout.meteor
return FindOne.__super__.constructor.apply(this, arguments);
}
- FindOne.prototype.createQuery = function(collection, selector, options) {
+ FindOne.prototype.createQuery = function(collection, selector, options, mapping) {
var data_func;
data_func = function() {
- return collection.findOne(selector, options.meteor_options);
+ return collection.findOne(selector, options);
};
- return new MappedQuery(this, data_func, options.mapping);
+ return new MappedQuery(this, data_func, mapping);
};
return FindOne;
View
12 examples/todo_list/example.js
@@ -40,22 +40,22 @@ if (Meteor.is_client) {
unfinishedTodos: ko.meteor.find(
Todos,
{done: false},
- {mapping: todoMapping}
+ {},
+ todoMapping
),
// Todos where 'done' == true
finishedTodos: ko.meteor.find(
Todos,
{done: true},
- {mapping: todoMapping}
+ {},
+ todoMapping
),
// The todo with the oldest 'created_at' where 'done' == false
oldestUnfinishedTodo: ko.meteor.findOne(
Todos,
{done: false},
- {
- meteor_options: {sort: {created_at: 1}},
- mapping: todoMapping
- }
+ {sort: {created_at: 1}},
+ todoMapping
)
};
View
2  package.json
@@ -1,7 +1,7 @@
{
"name": "knockout.meteor",
"description": "A Meteor-to-Knockout bridge",
- "version": "0.2.4",
+ "version": "0.3",
"repository": {
"type": "git",
"url": "git://github.com/steveluscher/meteor.knockout.git"
View
56 src/knockout.meteor.coffee
@@ -1,5 +1,5 @@
###
-Knockout Meteor plugin v0.2.4
+Knockout Meteor plugin v0.3
(c) 2012 Steven Luscher, Ruboss - http://ruboss.com/
License: MIT (http://www.opensource.org/licenses/mit-license.php)
@@ -19,11 +19,11 @@ class NotImplementedError extends Error
# These functions are exported as ko.meteor.find and ko.meteor.findOne
#
meteor =
- find: (collection, selector, options = {}) ->
- (new FindMany(collection, selector, options)).run()
+ find: (collection, selector, options = {}, mapping = {}) ->
+ (new FindMany(collection, selector, options, mapping)).run()
- findOne: (collection, selector, options = {}) ->
- (new FindOne(collection, selector, options)).run()
+ findOne: (collection, selector, options = {}, mapping = {}) ->
+ (new FindOne(collection, selector, options, mapping)).run()
#
# A Finder accepts a collection, selector, and options hash as arguments,
@@ -38,7 +38,7 @@ meteor =
# options - an Object, or a Knockout observable that returns an Object
#
class AbstractFinder
- constructor: (@collection, @selector, @options = {}) ->
+ constructor: (@collection, @selector, @options = {}, @mapping = {}) ->
@target = null
# If an argument to this finder happens to be a Knockout observable,
@@ -47,6 +47,7 @@ class AbstractFinder
ko.utils.unwrapObservable(@collection)
ko.utils.unwrapObservable(@selector)
ko.utils.unwrapObservable(@options)
+ ko.utils.unwrapObservable(@mapping)
return
.extend({throttle: 1}) # Defer, in case more than one argument changes at a time
.subscribe(@run) # Run every time changes are detected
@@ -59,24 +60,26 @@ class AbstractFinder
collection = ko.utils.unwrapObservable(@collection)
selector = ko.utils.unwrapObservable(@selector)
options = ko.utils.unwrapObservable(@options)
- @applyDefaults(options)
+ mapping = @processMapping(ko.utils.unwrapObservable(@mapping))
# Create a MappedQuery (as defined in subclass)
- @query = @createQuery(collection, selector, options)
+ @query = @createQuery(collection, selector, options, mapping)
# Run the query
@query.run()
- applyDefaults: (options) ->
- _.defaults options,
- mapping: {}
- view_model: null
+ processMapping: (raw_mapping) ->
+ mapping = _.clone(raw_mapping)
+
+ # Extract the view_model property
+ view_model = mapping.view_model
+ delete mapping.view_model
# If a root level mapping doesn't exist, create it
- options.mapping[""] = {} unless _.isObject(options.mapping[""])
+ mapping[""] = {} unless _.isObject(mapping[""])
# Merge in some mapping defaults
- _.defaults options.mapping[""],
+ _.defaults mapping[""],
# It's important to key collection members by their Mongo _id so that
# the Knockout Mapping plugin can determine if an object is new or old
key: (item) -> ko.utils.unwrapObservable(item._id)
@@ -84,34 +87,35 @@ class AbstractFinder
# If we were passed a view_model in the options hash,
# instruct the Knockout Mapping plugin to instantiate
# each Meteor record as an instance of that model
- if _.isFunction options.view_model
- options.mapping[""].create = (opts) ->
+ if _.isFunction view_model
+ mapping[""].create = (opts) ->
return ko.observable() unless opts.data
- view_model = new options.view_model(opts.data)
- ko.mapping.fromJS(opts.data, options.mapping, view_model)
-
- createQuery: (collection, selector, options) ->
+ ko.mapping.fromJS(opts.data, mapping, new view_model(opts.data))
+
+ mapping
+
+ createQuery: (collection, selector, options, mapping) ->
throw new NotImplementedError('createQuery')
class FindMany extends AbstractFinder
- createQuery: (collection, selector, options) ->
+ createQuery: (collection, selector, options, mapping) ->
# Set up the Meteor cursor for this selector
- meteor_cursor = collection.find(selector, options.meteor_options)
+ meteor_cursor = collection.find(selector, options)
# This is the function we want rerun when the result of this query changes
data_func = ->
meteor_cursor.rewind()
meteor_cursor.fetch()
- new MappedQuery(@, data_func, options.mapping)
+ new MappedQuery(@, data_func, mapping)
class FindOne extends AbstractFinder
- createQuery: (collection, selector, options) ->
+ createQuery: (collection, selector, options, mapping) ->
# This is the function we want rerun when the result of this query changes
- data_func = -> collection.findOne(selector, options.meteor_options)
+ data_func = -> collection.findOne(selector, options)
- new MappedQuery(@, data_func, options.mapping)
+ new MappedQuery(@, data_func, mapping)
#
# A MappedQuery monitors a finder for changes in its dataset. When it detects

No commit comments for this range

Something went wrong with that request. Please try again.