Search code examples
viewmodal-dialogsubmitslack-apislack-block-kit

Slack app opening new modal after previous modal submit is inconsistent, why?


I created a new free slack workspace to learn the slack bot app API. I have an action handler that listens to a global shortcut and opens an input modal in response. There is another action handler that listens to the modal input submit callback_id, does some work, and then uses the trigger_id to open another modal.

app.view('do_thing_b.submit', async (slack) => {

  try {
    await slack.ack()
    console.info(`Received modal submit`)

    // TODO: actual work to save the data

    const view = {
      type: 'modal',
      callback_id: 'do_thing_b.received_submission',
      title: {
        text: 'Thing B Done',
        type: 'plain_text',
      },
      blocks: [
        {
          type: 'section',
          text: {
            text: 'My Plain Text',
            type: 'plain_text',
            emoji: true,
          },
        },
      ],
      close: {
        text: 'Close',
        type: 'plain_text'
      }
    }

    const openViewParams = {
      trigger_id: slack.body.trigger_id,
      view,
    }
    console.log(`Opening Done Modal with open view params ${JSON.stringify(openViewParams)}`)
    const result = await slack.client.views.open(openViewParams)
    console.log(`=============================== Done modal opened?`)

    console.debug(result)
  }
  catch (err) {
    console.error(`Error submitting Thing B modal:`)
    console.error(err)
  }
})

The inconsistency is that this works as expected only when running the app in SocketMode against local code.

When I deploy the app and disable socket mode, the form submission never triggers the second modal to be displayed. I am able to see in the logs the same evidence of code behaviors that I see when running locally. The await slack.client.views.open(openViewParams) invocation succeeds and the result log indicates a 200 ok response from slack.

I have the same request URL set for events and interactivity as I do for the global shortcut. In fact, I also have a slash command that posts an ephemeral help screen to the user, similar to what the /polly command does. That message contains a button that also triggers this modal form to be displayed. Clicking that button to open the modal locally shows the same exact behavior: it works as expected when running locally with the app in Socket Mode, but never shows the followup modal after submission.

Follow-up question:

If this is not supposed to be allowed, how should slack apps respond to data input submission events? I also tried pushing a new view onto the modal, but closing the submit confirmation view just slides back to the original form, where I want it to close out the entire model. Do I need to send the user an ephemeral message to follow up after their data input submission?


Solution

  • Turns out I didn't need to open a modal, all I needed to do was update the existing modal. Instead of calling await slack.client.views.open with a trigger_id, I should have done this:

    app.view('do_thing_b.submit', async (slack) => {
    
      try {
        console.info(`Received modal submit`)
    
        // TODO: actual work to save the data
    
        const view = {
          type: 'modal',
          callback_id: 'do_thing_b.received_submission',
          title: {
            text: 'Thing B Done',
            type: 'plain_text',
          },
          blocks: [
            {
              type: 'section',
              text: {
                text: 'My Plain Text',
                type: 'plain_text',
                emoji: true,
              },
            },
          ],
          close: {
            text: 'Close',
            type: 'plain_text'
          }
        }
    
        const result = await slack.ack({
          response_action: 'update', view
        })
    
      }
      catch (err) {
        console.error(`Error submitting Thing B modal:`)
        console.error(err)
      }
    })
    

    The docs I kept missing are these: