Node-telegram-bot-api: ReplyKeyboardMarkup problem

Created on 28 Sep 2016  Â·  19Comments  Â·  Source: yagop/node-telegram-bot-api

Hi,
i saw various issues about this argument but still not working.

I used this code:

var yesno = {
        parse_mode: "Markdown",
        reply_markup: {
                ReplyKeyboardMarkup: {
                        "resize_keyboard": true,
                        "one_time_keyboard": true,
                        "keyboard": [["Yes"],["Back"]]
                }
        }
};

To reply a message without change function, but it doesn't print keybard so not work.
I tried without ReplyKeyboardMarkup but with force_reply, keyboard appers but not link to reply message.

var yesno = {
        parse_mode: "Markdown",
        reply_markup: {
                "force_reply": true,
                "resize_keyboard": true,
                "one_time_keyboard": true,
                "keyboard": [["Yes"],["Back"]]
        }
};

What can i do?
Thanks!

Most helpful comment

Yeah, there are two functions:

(From above)

Catching answers/replies:

bot.on("message", function(msg) {
     const callback = answerCallbacks[msg.chat.id];
     if (callback) {
         delete answerCallbacks[msg.chat.id];
         return callback(msg);
      }
});

This function will not be repeated, as it handles answer for all your queries. It only need to exist once.

Your query and answer:

bot.sendMessage(chatId, messageText).then(function() {
    // add a new 'answer' callback to receive the reply message
    answerCallbacks[chatId] = function(answer) {
        // ... do something with your answer ...
    };
});

All your logic remains together. As you see above, in the .then(), we are adding a new function to handle the query.

NOTE:

The implementation is quite premature. A better implementation can be drawn up.

All 19 comments

First, bot API parameters let you choose only one option among force_reply, InlineKeyboardMarkup, ReplyKeyboardMarkup, ReplyKeyboardHide. So, "keyboard", "resize_keyboard" and "one_time_keyboard" will be ignored due to _force_reply_.

Then, if I understood rightly your problem, as I solved in my issue topic, you can use Promise's _.then()_ method to set a new "waiting-for-a-reply" by not using bot.onReplyToMessage() but using EventEmitter 3 method

.once(trigger, callback)

which attach an event and then remove it once received the trigger (unlike _.on(trigger, callback)_, which doesn't remove the event).

This has to be done if your bot function is going to be built for a one-to-one interaction and not group interaction. Instead, you can put into your _.then()_ callback the already said _.onReplyToMessage()_.

In both cases as Object to be passed to _.sendMessage()_ is something like this:

const yesno = {
    parse_mode: "Markdown",
    reply_markup: {
        keyboard: [["Yes"], ["Back"]],
        resize_keyboard: true,
        one_time_keyboard: true,
    },
};

Just remember that by putting buttons in a way like that, you will always have two rows, with one button per row. You can also do

keyboard: [["Yes", "Back"]],

and they will be putted in two rows in case of small window/screen (depending by the device).

If I didn't understand correctly your problem, please answer back, explaining in a way more detailed.
I hope to have been helpful. 😉

Very useful! Thanks a lot!

Ehy @alexandercerutti i have a problem, with lots of users .once method seems to not work, when i push a button server ignore my response. But only when there are more of 50+ people simultaneously!
What can i do to fix this? Thanks a lot!

(ps sei italiano?)

Please, post your code. Maybe could be a server problem, I will not know 'till you don't post the code.

(Yes, I'm Italian, but I think it's better talk in English due to the common language here in the issues.)

Yes, so this is a little part of the code. But i can't understand why with 3-4 people works fine, when with lots of people nope.

bot.sendMessage(message.chat.id, "Are you sure?", yesno).then(() => {
     bot.once('message', (answer) => {
        //Code never executed when there are lots of people

        var res = answer.text;
              if (res == "Back to menu"){
                        return;
               }else if (res == "Yes"){
                         //other things
               }
      });
});

I think it could be a server problem... Where do you host your application?

Il 03 ott 2016 8:08 PM, "Edoardo Cortese" [email protected] ha
scritto:

Yes, so this is the code. Ma i can't understand why with 3-4 people works
fine, when with lots of people nope.

bot.sendMessage(message.chat.id, "Are you sure?", yesno).then(() => {
bot.once('message', (answer) => {
//Code never executed when there are lots of people

    var res = answer.text;
          if (res == "Back to menu"){
                    return;
           }else if (res == "Yes"){
                     //other things
           }
  });

});

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/yagop/node-telegram-bot-api/issues/197#issuecomment-251180359,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AFML8XQfvqsA0AlKPoOOXvXhT_v9Otciks5qwUSJgaJpZM4KIvnH
.

On a Dedicated OVH with i7, 32 Gb ram, 2 Tb
With apache, mysql and php

And Node.JS I suppose... That's seems to be a server problem that cannot accept all the requests... Anyway if yesno is the one I provided you, the condition should be

res === "Back"

Anyway, Which is the menu? Just terminating the function?

There's a logic error in your code.

bot.sendMessage(message.chat.id, "Are you sure?", yesno).then(() => {
     // this function is executed when the above message has been
     // successfully sent to the target chat

     // this registers an event handler to be invoked (only once) when
     // a message update is received.
     // To be clear, this listens for ANY message update. It does NOT
     // listen for a reply from this SPECIFIC user.
     // There's a possibility of this handler receiving a message from
     // ANOTHER user.
     bot.once('message', (answer) => {
        var res = answer.text;
              if (res == "Back to menu"){
                        return;
               }else if (res == "Yes"){
                         //other things
               }
      });
});

This means that, in situations where users are few, the bot.once() will most likely receive the correct user's reply, since the chances of another user sending us a message, while we wait for a reply (with bot.once()) is relatively low.

If the are many users, these chances increase. Thus, there might exist scenarios where the bot.once() handler receives a reply from the wrong user.

But which are other ways to wait for a message from a user when you cannot use _.onReplyToMessage()_ ? (based on my issue topic, linked above)

@alexandercerutti There is a bot.onText with '\back to menu\' that call main function, with main buttons.

@GochoMugo So, there is a way to handle only user confirm? Maybe with message.from.id or similar, idk.

Option 1:

Use the telegramBot.onReplyToMessage(chatId, messageId, callback) method.

Option 2:

Since we are sending and receiving messages from chats, you may do sth like:

const answerCallbacks = {};

// listening for message updates.
// If an 'answer' callback has been added on 'answerCallbacks',
// invoke it with the message (which is the 'answer'/reply)
bot.on("message", function(msg) {
     const callback = answerCallbacks[msg.chat.id];
     if (callback) {
         delete answerCallbacks[msg.chat.id];
         return callback(msg);
      }
});

bot.sendMessage(chatId, messageText).then(function() {
    // add a new 'answer' callback to receive the reply message
    answerCallbacks[chatId] = function(answer) {
        // ... do something with your answer ...
    };
});

@GochoMugo Thanks, so, i can't use the 1st option cause doesn't support reply by keyboard without manually reply the message (this is the cause of this post).
For the 2nd option, there is a way to do it in the same function, same bot.on, so i can avoid redeclare and query from database all of lots data?

Thanks a lot for patience.

@sidelux Am sorry I have not understood you query quite well. Do you mind elaborating?

@GochoMugo Sorry.

About Option 1:

Time ago i used this method but when i use keyboard to reply a message, bot can't catch this. If i say wrong correct me D:

About Option 2:

I could use this method, but i prefer to put all onText and answer in the same function, like code i posted earlier. As i see in your example there are two splitted functions.

I don't know that i'm stupid or only i haven't understand, so please, can you explain me the best method using the same function?

Yeah, there are two functions:

(From above)

Catching answers/replies:

bot.on("message", function(msg) {
     const callback = answerCallbacks[msg.chat.id];
     if (callback) {
         delete answerCallbacks[msg.chat.id];
         return callback(msg);
      }
});

This function will not be repeated, as it handles answer for all your queries. It only need to exist once.

Your query and answer:

bot.sendMessage(chatId, messageText).then(function() {
    // add a new 'answer' callback to receive the reply message
    answerCallbacks[chatId] = function(answer) {
        // ... do something with your answer ...
    };
});

All your logic remains together. As you see above, in the .then(), we are adding a new function to handle the query.

NOTE:

The implementation is quite premature. A better implementation can be drawn up.

Works perfectly! Thanks!!

@GochoMugo Great Option 2, thanks for it! Was searching smth like this for hours, cause couldn't imagine how to handle answers from users to bot questions. (Beside callback queries ofcourse)

Was this page helpful?
0 / 5 - 0 ratings