Bolt-js: Handling button after view submission?

Created on 29 Jan 2020  路  7Comments  路  Source: slackapi/bolt-js

Description

Dear developers, bolt is awesome, thanks for making this available!
I have a question about handling buttons after view submissions. My process is as follows:

  1. Post a message with one action button.
  2. Click the button and open a view.
  3. Submit the view.

In bolt, the app.view construct has an 'ack' function but not a 'say' or 'response' function. How would I update the action button at step (1) to show a user that this view was submitted? I want to disable that button.

I hope you can help me!

PS: this is related (https://github.com/slackapi/bolt/issues/305) but I think we can only use ack() for error handling.

What type of issue is this? (place an x in one of the [ ])

  • [ ] bug
  • [ ] enhancement (feature request)
  • [x] question
  • [ ] documentation related
  • [ ] testing related
  • [ ] discussion

Requirements (place an x in each of the [ ])

  • [x] I've read and understood the Contributing guidelines and have done my best effort to follow them.
  • [x] I've read and agree to the Code of Conduct.
  • [x] I've searched for any related issues and avoided creating a duplicate issue.

question

All 7 comments

Hey @robinpapa,

I haven't looked into this, but I think chat.update would allow you to update the original message (as well as the button). Want to try it out in your view submission handler?

Hey @robinpapa,

I haven't looked into this, but I think chat.update would allow you to update the original message (as well as the button). Want to try it out in your view submission handler?

Hi @stevengill! Thanks for your reply. I've started working on the chat.update solution, but how would you pass the original message block to the view in order to update the original message block once the view is submitted?

I'm having trouble figuring this out, maybe it's very simple.

I will store the original block in a temporary array and find it again based on an id that I can pass to the view and to the view submission. Then change the button to text and use the chat.update function to update the block.

Hey @robinpapa, I only just saw this issue but I have one more suggestion. You can use the private_metadata property of the modal view to store arbitrary info. In this case, you can store the ts and channel of the message with the button, so that you can use chat.update after submission to update it. This will help you avoid that temporary array, which can get tricky if your app has to restart or if you fail to clean up the entries correctly.

Ah, that's smart, @aoberoi ! Thank you, will try that!

EDIT: no, wait, then I still can't retrieve the original blocks right? Or is there a function to read the blocks if you have the ts and channel?

You could read the original blocks by using the conversations.history method. However, I wouldn't recommend this unless your app already needs the channels:history, groups:history, im:history, or mpim:history scopes. These scopes are generally considered by admins to be highly permissive, since they allow apps to read many many messages.

I'd instead recommend just copying the entire message (blocks and all) into the private_metadata of the dialog. When the button in the message is clicked, the action listener will have access to that message in the body argument, as body.message. You can serialize it to a string, and then JSON parse it back on the view submission. Here's an example:


app.action('my_button_action_id', async ({ ack, body }) => {
  // TODO: validate and perform any logic necessary to open the modal
  ack();

  // Generate private metadata for the modal
  let privateMetadata = '';
  if (body.message !== undefined) {
    privateMetadata = JSON.stringify(body.message);
  } else {
    // TODO: log and early return? this would be a logical issue and should never happen
  }

  await app.client.views.open({
    trigger: body.trigger_id,
    callback_id: 'my_modal',
    view: {
      type: 'modal',
      title: { type: 'plain_text', text: 'My Modal' },
      blocks: [ /* ... TODO: some blocks */ ],
      private_metadata: privateMetadata,
    },
  });

  // ...
});

app.view('my_modal', ({ ack, view }) => {
  // TODO: validate inputs
  ack();

  // Read original message from private metadata
  let originalMessage = undefined;
  try {
    const originalMessage = JSON.parse(view.private_metadata);
  } catch (error) {
    // TODO: log and early return?
  }

  // TODO: do the work

  // TODO: use chat.update to update the original message
});

@aoberoi That's the solution! JSONify the string. Thank you!

Was this page helpful?
0 / 5 - 0 ratings