You need to make sure that Meteor's reactive rendering does not destroy the DOM nodes created by iScroll, and re-instantiate iScroll when they do get destroyed and recreated. You also need to call iScroll.refresh() any time you change the DOM inside the scroller so it knows to update its dimensions.
Let's go through an example - say you have an template with a collection you want to scroll:
<template name="myCollectionView">
<div class="my_collection">
<div class="scroller">
{{#isolate}}
{{#each items}}
{{> item}}
{{/each}}
{{/isolate}}
</div>
</div>
</template>
Note that you need to double-wrap your collection with divs. The outer div my_collection
for passing to iScroll, and a single internal div scroller
that will actually get moved around by iScroll's JS.
Also note the #isolate
block around the items
- this tells Meteor to not propagate re-rendering outside of that block, so that when the collection changes, the outer DOM (the wrapper and the scroller nodes) don't get replaced.
Now let's initialize iScroll and add appropriate bookkeeping to keep it running when DOM changes by Meteor's reactivity:
var scroller; // file-scope instance of iScroll that we will update appropriately
...
Template.myCollectionView.rendered = function () {
var scrollNode = this.find('.scroller');
// let's figure out if iScroll is already running by checking whether
// it's DOM nodes are still intact.
if (scrollNode.style.webkitTransform == "") {
// either first time rendering, or someone replaced our DOM nodes.
// Re-instantiate iScroll.
scroller = new iScroll(this.find('.my_collection'));
} else {
// DOM is still intact, just tell iScroll to update its size
// You need to do this in a setTimeout to make sure DOM changes
// have already been rendered (this affects size computations)
Meteor.setTimeout(function () { scroller.refresh(); }, 0);
}
}
Make sure you have overflow: hidden;
set in CSS for your wrapper div (i.e. .my_collection
), and you are good to go.