bootbot icon indicating copy to clipboard operation
bootbot copied to clipboard

Passing arguments to events subscriptions

Open caiolopes opened this issue 8 years ago • 18 comments

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

caiolopes avatar Feb 08 '17 16:02 caiolopes

Hey @caiolopes, my workaround is the following:

  1. stringify the object that I want to pass as payload
  2. 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 avatar Feb 09 '17 23:02 kebou

@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?

caiolopes avatar Feb 10 '17 02:02 caiolopes

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.

kebou avatar Feb 10 '17 16:02 kebou

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 avatar Feb 17 '17 07:02 Charca

@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 avatar Feb 23 '17 23:02 caiolopes

@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 avatar Feb 23 '17 23:02 Charca

@Charca Yes, exactly! Can I try to implement this and make a PR?

caiolopes avatar Feb 23 '17 23:02 caiolopes

@caiolopes absolutely, go ahead!

Charca avatar Feb 23 '17 23:02 Charca

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!

kebou avatar Feb 24 '17 00:02 kebou

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 :)

dlocation avatar Feb 24 '17 22:02 dlocation

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

rohit-git7 avatar Mar 25 '17 20:03 rohit-git7

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 avatar Mar 27 '17 20:03 Charca

@Charca @kebou Does anyone know if facebook has maximum allowed length for the payload?

mmayla avatar Apr 27 '17 20:04 mmayla

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' 
}

mmayla avatar Apr 27 '17 22:04 mmayla

@Charca is this still a relevant issue (the postback part)? I will move the regex thread here to a new issue.

mraaroncruz avatar Nov 25 '17 14:11 mraaroncruz

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.

Charca avatar Nov 25 '17 23:11 Charca

Hi , I have a question : how my bot knows if a user is active ?? thanks

WIEM-S avatar Jun 13 '18 12:06 WIEM-S

@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.

Charca avatar Jun 14 '18 11:06 Charca