Meteor observeChanges runs before screen reactivity

93 Views Asked by At

I'm using Collections.observe in my chat app. After submitted one message, all the users needs to be scrolled down to appear the new message.

I am trying:

Messages.find().observe({
  added: function() {
    $('.messages').scrollTop($('.messages')[0].scrollHeight); // scroll to bottom
  }
});

However, this function execute before the message appears in the screen. But I need the observe function to execute AFTER the message appears on the screen, to scroll down. How can I do that?

2

There are 2 best solutions below

0
On BEST ANSWER

Maybe you should use this.autorun() in an onRendered event in template with .messages elem. I mean something like:

Template.myTemplate.onRendered(function () {
    this.autorun(function () {
        if (Messages.find().count() /*or some more specific reactive dep*/) {
            this.$('.messages').scrollTop(this.$('.messages')[0].scrollHeight);
        }
    }.bind(this))
})
0
On

You could wrap it in a Meteor.defer or a Tracker.afterflush. But those are a slippery slope.

Ideally, observe should be reserved for 3rd party APIs (like maps, d3js, etc). By having an observe out there for something simple like a scroll, and then your template + helpers handling the same thing, your code is gonna be a hot mess in terms of MVC.

What I'd do instead, is put an index in your helper. When the index === collection.cursor.count(), you know you're at the most recent message, and then you can scroll to that template instance. (I'm assuming each message has it's own template here).