I use Bolt and I'm attempting to use app.client.views.open and app.client.views.update and I'm running into an issue. I have no issues opening the modal, but when the user submits I want to call app.client.views.update and update the modal.
This is an issue because if I do not use ack(), I am getting an error on the successfully updated view “[ERROR] WebClient:0 Error: An incoming event was not acknowledged before the timeout. Ensure that the ack() argument is called in your listeners.”. But, if I do respond with ack(), before calling app.client.views.update then the modal closes and the update is never received?
The code examples you provided here https://slack.dev/bolt/concepts#updating-pushing-views do not work.
x in one of the [ ])x in each of the [ ])package version: 1.4
node version: v12.1.0
OS version(s): Ubuntu 16.04.6 LTS
The modal should be updated and stay opened.
The modal disappeared after the app.client.views.update call.
1|test-node | [ERROR] WebClient:0 Error: An incoming event was not acknowledged before the timeout. Ensure that the ack() argument is called in your listeners.
I found a solution. In my case I tried to use app.view. It works with app.action.
@vidanov When you're acknowledging a view_submission event, you can include a response_action which allows you to update the view. This method doesn't use app.client.views.update, you'll just pass the JSON directly into the ack() function. When you pass nothing into ack, it defaults to closing the modal.
Response actions are detailed a bit in the documentation. A basic example with bolt is:
```
app.view('CALLBACK_ID', ({ ack, view } => {
ack({
"response_action": "update",
"view": {
"type": "modal",
"title": {
"type": "plain_text",
"text": "Updated view"
},
"blocks": [
{
"type": "section",
"text": {
"type": "plain_text",
"text": "I've changed and I'll never be the same. You must believe me."
}
}
]
});
console.log(view);
});
@shanedewael Thank you! I missed this example here:
https://slack.dev/bolt/concepts#creating-modals
Is there anything special about what cannot go into the blocks section? If I put any of the input elements, it wont work and gives an error.
For example:
"blocks": [
{
"type": "section",
"text": {
"type": "plain_text",
"text": "I've changed and I'll never be the same. You must believe me."
}
},
{
type: "input",
element: {
type: "radio_buttons",
options: [
{
text: {
type: "plain_text",
text: "*this is plain_text text*",
emoji: true
},
value: "value-0"
},
]
},
label: {
type: "plain_text",
text: "Label",
emoji: true
}
}
]
@rnaimi No it isn't. Your blocks seem to be valid. Are you using views.update API method call in app.view listener as with the original question here? If so, tell the same thing using ack() method with valid response_action instead.
I'm responding back this in my call to ack() to a view_submission callback. When I do this, the original modal view that submitted the view_submission stays on, and after I call the ack, it displays "We had some trouble connecting. Try again?". If I take out the input element, it works fine and shows the section with static text.
response_action: "update",
view: {
type: 'modal',
callback_id: 'second_step_callback_id',
title: {
type: 'plain_text',
text: 'Second step',
},
submit: {
type: "plain_text",
text: "Submit",
emoji: true
},
close: {
type: "plain_text",
text: "Cancel",
emoji: true
},
blocks: [
{
type: "section",
block_id: "section_890",
text: {
type: "mrkdwn",
text: "*This is second step in a multi-step workflow.*"
}
},
{
type: "input",
element: {
type: "radio_buttons",
options: [
{
text: {
type: "plain_text",
text: "*this is plain_text text*",
emoji: true
},
value: "value-0"
},
]
},
label: {
type: "plain_text",
text: "Label",
emoji: true
}
}
],
}
If I take out the input element, it works fine and shows the section with static text.
hmm, I just tried both pattens out but they work for me. Probably, the error might be related to other reasons.
When you use the ack() method to send a view, there is no way to get the reason for its error. So, when you encounter something wrong with it, I recommend using Block Kit Builder to verify the blocks you compose (as I did in the previous comment).
Thanks a lot for your quick response. I got it partially working. It doesn't give me an error anymore, but it also doesn't behave as I expected. The reason why it was giving me an error was because I was mistakenly calling ack () without await... I fixed that by
await ack (response_content);
However, I am still having a problem with updating the view. My original view has a number of input fields (see the first section). When I send the update response through ack, I fill in the fields with initial_value attribute (see the second section). What I expected to see was the form with the values filled in. What I see is the form with empty fields.
initial form:
{
view: {
type: 'modal',
title: {
type: 'plain_text',
text: 'Find Contact'
},
clear_on_close: true,
notify_on_close: true,
callback_id: 'do_find_contact',
submit: {
type: 'plain_text',
text: 'Find'
},
close: {
type: 'plain_text',
text: 'Cancel'
},
blocks: [
{
label: {
type: 'plain_text',
text: 'Email'
},
type: 'input',
block_id: 'email',
element: {
type: 'plain_text_input',
action_id: 'email'
},
optional: true
},
{
type: 'input',
block_id: 'firstname',
element: {
type: 'plain_text_input',
action_id: 'firstname'
},
label: {
type: 'plain_text',
text: 'First Name'
},
optional: true
},
{
type: 'input',
block_id: 'lastname',
element: {
type: 'plain_text_input',
action_id: 'lastname'
},
label: {
type: 'plain_text',
text: 'Last Name'
},
optional: true
},
{
type: 'input',
block_id: 'phone',
element: {
type: 'plain_text_input',
action_id: 'phone'
},
label: {
type: 'plain_text',
text: 'Phone Number'
},
optional: true
}
]
}
}
this is what I send back through ack:
{
view: {
type: 'modal',
title: {
type: 'plain_text',
text: 'Contact Details'
},
clear_on_close: true,
notify_on_close: true,
callback_id: 'do_update_contact',
submit: {
type: 'plain_text',
text: 'Update'
},
close: {
type: 'plain_text',
text: 'Cancel'
},
blocks: [
{
label: {
type: 'plain_text',
text: 'Email'
},
type: 'input',
block_id: 'email',
element: {
type: 'plain_text_input',
action_id: 'email',
initial_value: '[email protected]'
},
optional: true
},
{
type: 'input',
block_id: 'firstname',
element: {
type: 'plain_text_input',
action_id: 'firstname',
initial_value: 'John'
},
label: {
type: 'plain_text',
text: 'First Name'
},
optional: true
},
{
type: 'input',
block_id: 'lastname',
element: {
type: 'plain_text_input',
action_id: 'lastname',
initial_value: 'Smith'
},
label: {
type: 'plain_text',
text: 'Last Name'
},
optional: true
},
{
type: 'input',
block_id: 'phone',
element: {
type: 'plain_text_input',
action_id: 'phone',
initial_value: '6501234567'
},
label: {
type: 'plain_text',
text: 'Phone Number'
},
optional: true
}
]
},
response_action: 'update'
}
@rnaimi
If you use the same pair of block_id and action_id even after updating a modal, the updating operation keeps the previous state for those inputs. That's why those input values are not replaced with the initial_value. You can change either block_id or action_id for reflecting the initial_value anyways. As your second view has a different callback_id, I do understand the behavior may be a bit surprising but for now, going with different names for blocks would be the quickest way to realize the app you want to build.
thank you!!!! I spent 2 days trying to figure out what was wrong... That worked.
One thing that still puzzles me is that when I update the view with the initial_value for the fields, if I cancel out of the modal, it asks "Are you sure you want to leave?" as if there is a dirty flag that was set even if the values are unchanged. Is there a parameter or API call that I can make to clear the dirty flag?
I think I figured it out... Apparently if I change block_id, then the modal can be dismissed without prompt. If I only change the action_id, then modal thinks there were fields that were modified so it prompts.
Thanks again for your help.
I tried first sending a message along with ack({update view}) that we are validating the data then I posted the updated view using views.update. Then it worked for me. Cheers!👍
Most helpful comment
@vidanov When you're acknowledging a
view_submissionevent, you can include aresponse_actionwhich allows you to update the view. This method doesn't useapp.client.views.update, you'll just pass the JSON directly into theack()function. When you pass nothing into ack, it defaults to closing the modal.Response actions are detailed a bit in the documentation. A basic example with bolt is:
```
app.view('CALLBACK_ID', ({ ack, view } => {
ack({
"response_action": "update",
"view": {
"type": "modal",
"title": {
"type": "plain_text",
"text": "Updated view"
},
"blocks": [
{
"type": "section",
"text": {
"type": "plain_text",
"text": "I've changed and I'll never be the same. You must believe me."
}
}
]
});
console.log(view);
});