Question

I'm having a problem getting iScroll (v5) to work with Meteor. I've installed the package no problem but calling iScroll when the document has loaded is proving a bit of a pain.

Meteor doesn't support body onload like in the iScroll demo so I tried:

if (Meteor.isClient) {
  Meteor.startup(function () {
    var myScroll;
myScroll = new IScroll('#wrapper', { mouseWheel: true });
document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);
});

}

in my main.js file.

This seems to only work after I refresh the page and doesn't run when I navigate to a new page.

I also tried to add the initialization code to the Template.rendered function on the main page of my application. Again it seems to work sometimes and not others??

Sorry if I've being a noob but Meteors template rendering is proving hard to get my head around.

Any help anyone can offer would be extremely appreciated!!!

Stephen

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top