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

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)

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);
     }
 });
});

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.

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

Monday morning bump!

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

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.

What should the condition be for the #if statement?

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.

1 Like

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!

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:

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

1 Like

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