diff --git a/packages/spark/spark.js b/packages/spark/spark.js index 52c28be6ba..f869f7632b 100644 --- a/packages/spark/spark.js +++ b/packages/spark/spark.js @@ -865,8 +865,10 @@ Spark.list = function (cursor, itemFunc, elseFunc) { } } initialContents = null; // save memory + var stopped = false; var cleanup = function () { handle.stop(); + stopped = true; }; html = annotate(html, Spark._ANNOTATION_LIST, function (range) { outerRange = range; @@ -894,10 +896,17 @@ Spark.list = function (cursor, itemFunc, elseFunc) { walk.rendered.call(walk.landmark); }; + var later = function (f) { + atFlushTime(function () { + if (! stopped) + f(); + }); + }; + // The DOM update callbacks. _.extend(callbacks, { added: function (item, beforeIndex) { - atFlushTime(function () { + later(function () { var frag = Spark.render(_.bind(itemFunc, null, item)); DomUtils.wrapFragmentForContainer(frag, outerRange.containerNode()); var range = new LiveRange(Spark._TAG, frag); @@ -915,7 +924,7 @@ Spark.list = function (cursor, itemFunc, elseFunc) { }, removed: function (item, atIndex) { - atFlushTime(function () { + later(function () { if (itemRanges.length === 1) { var frag = Spark.render(elseFunc); DomUtils.wrapFragmentForContainer(frag, outerRange.containerNode()); @@ -930,7 +939,7 @@ Spark.list = function (cursor, itemFunc, elseFunc) { }, moved: function (item, oldIndex, newIndex) { - atFlushTime(function () { + later(function () { if (oldIndex === newIndex) return; @@ -948,7 +957,7 @@ Spark.list = function (cursor, itemFunc, elseFunc) { }, changed: function (item, atIndex) { - atFlushTime(function () { + later(function () { Spark.renderToRange(itemRanges[atIndex], _.bind(itemFunc, null, item)); }); } diff --git a/packages/spark/spark_tests.js b/packages/spark/spark_tests.js index f217a3c039..e121206310 100644 --- a/packages/spark/spark_tests.js +++ b/packages/spark/spark_tests.js @@ -3526,3 +3526,50 @@ Tinytest.add("spark - unique label", function (test) { test.equal(bufstr(), 'ddd'); }); + +Tinytest.add("spark - list update", function (test) { + var R = ReactiveVar('foo'); + + var lst = []; + lst.callbacks = []; + lst.observe = function(callbacks) { + lst.callbacks.push(callbacks); + _.each(lst, function(x, i) { + callbacks.added(x, i); + }); + return { + stop: function() { + lst.callbacks = _.without(lst.callbacks, callbacks); + } + }; + }; + lst.another = function () { + var i = lst.length; + lst.push({_id:'item'+i}); + _.each(lst.callbacks, function (callbacks) { + callbacks.added(lst[i], i); + }); + }; + var div = OnscreenDiv(Meteor.render(function() { + return R.get() + Spark.list(lst, function () { + return '
'; + }); + })); + + lst.another(); + Meteor.flush(); + test.equal(div.html(), "foo
"); + + lst.another(); + R.set('bar'); + Meteor.flush(); + test.equal(div.html(), "bar

"); + + R.set('baz'); + lst.another(); + Meteor.flush(); + test.equal(div.html(), "baz


"); + + div.kill(); + Meteor.flush(); +});