bootbot
bootbot copied to clipboard
Passing arguments to events subscriptions
Hi!!
I have a question about how to pass information from a button event to the the button subscription..
I modified the bootbot source code to work something out, but I would to confirm if there is another way before I make a pull request. It is something like:
chat.say({
text: 'Some product here',
buttons: [
{ type: 'postback', title: 'More info', payload: 'INFO:product_id' }
]
});
bot.on('postback:INFO', (payload, chat, data, args) => {
console.log(args); // should print "product_id"
});
Hey @caiolopes, my workaround is the following:
- stringify the object that I want to pass as payload
- subscribe to all postback messages, parse the payload string as JSON and decide the type of the postback
Here is the code with your example:
chat.say({
text: 'Some product here',
buttons: [{
type: 'postback',
title: 'More info',
payload: JSON.stringify({
type: 'INFO',
product_id: 'PRODUCT_ID'
})
}]
});
bot.on('postback', (payload, chat, data) => {
const pb_payload = JSON.parse(payload.postback.payload);
if (pb_payload.type == 'INFO') {
console.log(pb_payload.product_id);
}
});
@kebou nice solution! I think this could be implemented in a native way in the bootbot!
I am just wondering if the list of if statements can get really long, don't you think?
yep, you're right, it would be great to have a similar built in feature, however the code won't be shorter, because subscribing for every specific event or checking the type of the payload with if statements requires nearly the same length of code, but it would be without doubt more consistent.
I like this idea, I can see the use for something like this, and there's definitely room to implement it, we could use the data
param that is currently not implemented for postback events.
I'm thinking we could establish a pattern for arguments (I like the :
as a separator) and send them back to the callback in the data
object:
chat.say({
text: 'Some product here',
buttons: [
{ type: 'postback', title: 'More info', payload: 'INFO:product_id:user_id:promo_id' }
]
});
bot.on('postback:INFO', (payload, chat, data) => {
console.log(data.args); => [ 'product_id', 'user_id', 'promo_id' ]
});
We could even have named arguments so data.args
become an object instead of an array, but I'm not sure what's the limit of characters in the postback string and I don't wanna push it.
In the case of a callback listening for a particular postback + argument combination, we will execute both. So for example if you have a button with postback INFO:123456
and these two listeners:
bot.on('postback:INFO', () => {} );
bot.on('postback:INFO:123456', () => {} );
Both will be called, and the data.captured
flag will be set to true
.
Thoughts?
@Charca I liked your suggestion but I think it is easier and transparent for someone using the project pass an object instead of having to follow some unusual pattern.
I don't think the limit of characters is gonna be a problem since it is not meant to pass too much data. For example, in my case, I used only for passing ids so I could search in the database for information, etc.
In that case, I really enjoyed @kebou suggestion, but instead of doing the JSON parse yourself and a lot of ifs statements, just pass an object and the correct postback callback is gonna be called!
It would require one property in this object for identifying the the callback, and the rest could be anything set by the user and passed trough the data object as you mentioned.
@caiolopes I agree. So just to make sure we're on the same page, we're talking about something on the lines of:
chat.say({
text: 'Some product here',
buttons: [{
type: 'postback',
title: 'More info',
payload: {
name: 'INFO',
arguments: [ 'PRODUCT_ID' ]
}
}]
});
bot.on('postback:INFO', (payload, chat, data) => {
console.log(data.arguments); // => [ 'PRODUCT_ID' ]
});
Correct?
@Charca Yes, exactly! Can I try to implement this and make a PR?
@caiolopes absolutely, go ahead!
Hey guys, I really like the idea, it will be great!
@caiolopes let me share with you this code snippet (what I found earlier), maybe it can help you during the JSON validation/parsing, because separate a string from a stringified object is harder than it seems.
const tryParseJSON = (jsonString) => {
try {
var o = JSON.parse(jsonString);
// Handle non-exception-throwing cases:
// Neither JSON.parse(false) or JSON.parse(1234) throw errors, hence the type-checking,
// but... JSON.parse(null) returns null, and typeof null === "object",
// so we must check for that, too. Thankfully, null is falsey, so this suffices:
if (o && typeof o === "object") {
return o;
}
}
catch (e) { }
return false;
}
Good luck!
Hi guys. I think that also worth implement support of regexp parameters of postback events as at bot.hear(). I look forward to a solution of this issue. P.S Charca, thank you for awesome and lightweight lib. You rock :)
Hi everyone, As @deonisnov mentioned, I also need support of regexp parameters of postback events as at bot.hear().. Can somebody explain a way out?
Thanks, Rohit
PRs are welcome. If no one is able to take this one I'll grab it after I'm done with the currently open PRs (hopefully tonight or tomorrow).
@Charca @kebou Does anyone know if facebook has maximum allowed length for the payload?
I just tested it out the maximum length of the payload is 1000. and facebook return an error with code 100
{
message: '(#100) Length of param [buttons][1][payload] must be less than or equal to 1000',
type: 'OAuthException',
code: 100,
fbtrace_id: 'D2BEe5nhiIE'
}
@Charca is this still a relevant issue (the postback part)? I will move the regex thread here to a new issue.
I think this would make for a pretty cool feature. Grabbing data passed in the postback's name is a pretty common use case, and providing an easy way to access that data on the callback function would be really useful.
I'll leave this open, if anyone wants to take a crack at it, please go ahead.
Hi , I have a question : how my bot knows if a user is active ?? thanks
@WIEM-S What do you mean by active? If you want to know if the user is currently using the Messenger app, I don't think there's a way to know that for sure.