How to use Iron Router to scroll to a page position on a particular route?


#1

I’m trying this:

Router.route('/get-started', {
  template: 'landingPage',
  onAfterAction: function () {
    Tracker.afterFlush(function () {
      $('html,body').scrollTop(3000);
    });
  }
});

But it’s not working. The / route also uses the landingPage template. So the goal here is, if a user navigates to /get-started, they’re still on the landing page but it’ll jump them down. (and yes, I realize I need to programatically get the ID position and jump to that… the hardcoded 3000 is just for testing)


#2

Not sure why it doesn’t work within the route but I guess you could stick it all in the onRendered function of the template. Not able to check the below at the moment so it might have a few typos in but I think the concept should work. Getting the route name like that with Iron Router is reactive I believe so it’ll rerun on change.

Template.templateName.onRendered(function() {
  var instance = this;
  instance.autorun(function() {
     var routeName = Router.current().route.getName();
     if (routeName === 'get-started') {
          $('html,body').scrollTop(3000);
     }
 });
});

#3

I was just about to try that. So here’s what I’ve got now:

Template.landingPage.onRendered(function () {
  this.autorun(() => {
    if (this.subscriptionsReady()) {
      let routeName = Router.current().route.getName();

      if (routeName === 'get-started') {
        $('html, body').scrollTop(3000);
      }
    }
  });
});

I had to wait for a subscription on the landing page first. But it still doesn’t work. However, if I put a delay in the publication:

Meteor.publish('products', function () {
  Meteor._sleepForMs(2000);
  return Products.find({hidden: false});
});

Then it works! Very strange, I can’t wrap my head around this one.


#4

And the usual solution of adding Tracker.afterFlush didn’t help either. :confused:


#5

Monday morning bump!


#6

this.subscriptionsReady() couldnt help you in this case. If your DOM depends on sub data then you should know that this.subscriptionsReady() > Tracker.afterFlush > scrollTop() isnt the same as this.subscriptionsReady() > DOM Rendered (page has its real height) > scrollTop()

So you should separate the sub and the view that you want to scroll on rendered. I mean your logic have to looks like:

  1. render parent template with subscribtions
  2. wait for subs are ready inside parent
  3. render child template from parent (just use Blaze {{#if <...>}} {{> childTemplate}} {{/if}})
  4. scroll the page on child template with onRendered with afterFlush

#7

But the page scroll code is inside Template.landingPage.onRendered, shouldn’t that only execute once the DOM has rendered?

My template structure is as follows:

layoutTemplate (subs: none)
  landingPage (subs: products)

And the landingPage template is subscribing to products:

Template.landingPage.onCreated(function () {
  this.subscribe('products');
});

I guess I’m not understanding how all this ties together.


#8

What should the condition be for the #if statement?


#9

Sadly, this doesn’t work.

##landing-page.html

{{#if Template.subscriptionsReady}}
  {{> products}}
{{else}}
  <div class="content-load">
    <i class="fa fa-spinner fa-pulse"></i> Loading Products
  </div>
{{/if}}

##landing-page.es6.js

Template.landingPage.onCreated(function () {
  this.subscribe('products');
});

##products.html

<template name="products">
  <section class="products">
    <div class="container">
      <div class="row">
        {{#each products}}
          {{> singleProduct}}
        {{/each}}
      </div>
    </div>
  </section>
</template>

##products.es6.js

Template.products.onRendered(function () {
  Tracker.afterFlush(function () {
    let routeName = Router.current().route.getName();

    if (routeName === 'get-started') {
      $('#loc-get-started').velocity('scroll');
    }
  });
});

Template.products.helpers({
  products () {
    return Products.find();
  }
});

This is the one thing I dislike about Meteor. The order of processing/rendering is very unclear to me. It shouldn’t take me more than an hour to figure out how to do this.


#10

Are you shure it works from console after your page is ready? Could it be that something else does matter on the page height? I’ve tried a clean meteor project and it works man!


#11

The scrolling definitely works if I run it from the console after the page is already loaded. I dunno, this one is super confusing and I can’t seem to figure it out. It’s a major bummer :frowning:


#12

It could matters nothing but try to set a breakpoint in onRendered and on code stops run scroll from console. I’ve hade similar with adding a class for transition with min-width


#13

DUH! I feel stupid. okgrow:iron-router-autoscroll was installed, so it was jumping to the top immediately after my code executed.