Adrian Krebs
Adrian Krebs

Reputation: 4387

Scroll to bottom of chat after response from chatbot in meteor

I'm building a simple chatbot app with meteor. When the user sends a text message, the text is forwarded to my chatbot api. When I get the response back from the request I want to scroll to the bottom of my chat.

I found this answer on stackoverflow: How do I scroll to the bottom of a div as data is added in Meteor?

When the user sends a message the scrolling works, but as soon as I get the response back from my chatbot the scrollbar isn't at the bottom anymore. Do i have to wait till the insertion of the response is completed?

What am I missing?

User adds a new message:

Template.chat.events({
'submit .new-message'(event) {
    // Prevent default browser form submit
    event.preventDefault();

    // Get value from form element
    const target = event.target;
    const text = target.text.value;
    const chatId = FlowRouter.getParam("chatId");

    // Insert a task into the collection

    const callback = function () {
        let messages = document.getElementById('messages');
        setTimeout(() => {
            messages.scrollTop = messages.scrollHeight;
        }, 300);
    }
    Meteor.call('messages.insert', text, chatId,callback);

    // Clear form
    target.text.value = '';

    }
});

And here is the part where i call my chatbot api to process the user input and respond accordingly (insert response to collection, scroll to bottom):

Meteor.methods({
'messages.insert'(text, chatId, callback) {

    check(text, String);

    Messages.insert({
        text,
        chatId,
        user: true,
        createdAt: new Date()
    });

    let options = {
        sessionId: chatId
    };

    let request = app.textRequest(text, options);

    request.on('response', Meteor.bindEnvironment(function (response, errror) {
        text = response.result.fulfillment.speech + '<br><br><button class="js-yes">Ja</button><button class="js-no">Nein</nein>';

        Messages.insert({
            text,
            chatId,
            user: false,
            createdAt: new Date()
        });
        callback();

    }, function (error) {
        console.log(error);
    }));

    request.end();

}
});

and here the html:

<template name="chat">
  <ul id="messages">
    {{#each messages}}
      {{> message}}
    {{/each}}
  </ul>
  <form class="new-message">
    <input type="text" name="text" autocomplete="off" placeholder="Write a new message" />
  </form>
</template>

with its css part:

#messages {
    height: 500px;
    overflow-y: scroll;
}

Upvotes: 0

Views: 1281

Answers (1)

Mikkel
Mikkel

Reputation: 7777

I think if you move your callback function:

const callback = function () {
    let messages = document.getElementById('messages');
    setTimeout(() => {
        messages.scrollTop = messages.scrollHeight;
    }, 300);
}

To be called by the helper method that runs when the collection is updated, and then you can dispense with the call you make after the insert, because it will run whoever updates the collection. You might want to give it a better name than "callback" while you are doing it

Upvotes: 1

Related Questions