diff --git a/examples/unfinished/shark/client/shark.js b/examples/unfinished/shark/client/shark.js
index 794b78a544..098e018918 100644
--- a/examples/unfinished/shark/client/shark.js
+++ b/examples/unfinished/shark/client/shark.js
@@ -4,9 +4,11 @@ Items.insert({ text: 'Bar' });
Items.insert({ text: 'Baz' });
Meteor.startup(function () {
- Items.insert({ text: 'Qux' });
- Items.remove({ text: 'Foo' });
- Items.update({ text: 'Bar' }, { text: 'Car' });
+ Meteor.setTimeout(function () {
+ Items.insert({ text: 'Qux' });
+ Items.remove({ text: 'Foo' });
+ Items.update({ text: 'Bar' }, { text: 'Car' });
+ }, 1000);
});
Body({
@@ -106,13 +108,14 @@ Either = UIComponent.extend({
elseContent: Span
}),
{ type: Span });
- /* buf(new _UI.Each({
+ buf(new _UI.Each({
+ data: function () { return Items.find({}, { sort: { text: 1 }}); },
content: UIComponent.extend({
render: function (buf) {
- buf("
Each ", String(this.data()), "
");
+ buf("Each ", this.data().text, "
");
}
})
- }));*/
+ }));
}
});
diff --git a/packages/ui/base.js b/packages/ui/base.js
index 6ff636919f..18bc53f81b 100644
--- a/packages/ui/base.js
+++ b/packages/ui/base.js
@@ -17,7 +17,7 @@ var constrImpl = function (ths, args, type) {
if (! (ths instanceof type))
// invoked without `new`
- return new type;
+ return new type(args[0], args[1]);
// invoked as `new Foo(...)`
if (! type._superSealed)
@@ -236,7 +236,9 @@ _extend(Component, {
Component.include({
constructed: function () {},
- data: function () { return null; }
+ data: function () {
+ return this.parent ? this.parent.data() : null;
+ }
});
// @export UIComponent
diff --git a/packages/ui/components.js b/packages/ui/components.js
index c31474f1a5..0e894e0a31 100644
--- a/packages/ui/components.js
+++ b/packages/ui/components.js
@@ -34,6 +34,47 @@ _UI.If = Component.extend({
}
});
+_UI.Each = Component.extend({
+ typeName: 'Each',
+ render: function (buf) {
+ var self = this;
+
+ // XXX support arrays too.
+ // XXX and objects.
+ // For now, we assume the data is a database cursor.
+ var cursor = self.data();
+ // XXX support null
+
+ // id -> component
+ var items = self.items = new OrderedDict(Meteor.idStringify);
+
+ cursor.observe({
+ _no_indices: true,
+ addedAt: function (doc, i, beforeId) {
+ var comp = self.content(function () {
+ this.dataDep.depend();
+ return this._data;
+ }, {
+ _data: doc,
+ dataDep: new Deps.Dependency
+ });
+ // XXX could `before` be a falsy ID? Technically
+ // idStringify seems to allow for them -- though
+ // OrderedDict won't call stringify on a falsy arg.
+ items.putBefore(doc._id, comp, beforeId);
+ }
+ });
+
+ if (items.empty()) {
+ buf(self.elseContent());
+ } else {
+ items.forEach(function (comp) {
+ buf(comp);
+ });
+ }
+ }
+});
+
_UI.Counter = Component.extend({
typeName: "Counter",
fields: {