Add-ons can contribute Views in HipChat modal Dialogs. Dialogs should only be used for interrupt flows, e.g. "select and post a meme". If the content of the View is meant to provide more context in the conversation, you should use the Sidebar - Archived instead.
Modals can be used to gather critical input from the user such as integration configuration preferences. Modal dialogs are used to get a response from a user, to reveal critical information that cannot be ignored, or to show data without losing the overall context. Interactions on the main page must wait for the dialog to close.
Actions
The main action should be a primary button, other actions should be link buttons. In most cases, there should only be two actions.
The 'x' button in the top right of the modal is used to close the dialog window. Note this is only visible if the dialog does not use a bottom bar and therefore does not have a 'Close' or 'Cancel' link button.
Consider
API reference
API reference for dialogs: Dialog API Reference
To use a dialog, your add-on must first declare a dialog in its descriptor:
Descriptor
1 2"capabilities": { ..., "dialog": [ { "key": "myaddon-dialog", "title": { "value": "An add-on dialog title" }, "url": "{{localBaseUrl}}/dialog" } ] }
These are the minimal required properties. You can also specify options to customize the look and feel of your dialog. All of these are purely optional:
Descriptor
1 2"capabilities": { ..., "dialog": [ { "key": "myaddon-dialog", "title": { "value": "A Dialog Title" }, "url": "{{localBaseUrl}}/dialog/complex", --> The url of the dialog contents "options": { "style": "normal", --> Can also be "warning", for an error or warning dialog "primaryAction": { --> The primary action button "name": { "value": "Yes" }, "key": "dialog.yes", --> The key is needed if you want to handle the button click "enabled": false --> Is true by default, but you can set it to false if you want to enable the button dynamically }, "secondaryActions": [ --> If not specified, a default "Close" button will be rendered. You can declare an empty array for no secondary actions. { "name": { "value": "No" }, "key": "dialog.no" --> The key is only needed if you want to handle the button click } ], "size": { --> Alternatively, you can specify "size": "small" or "medium" or "large" or "xlarge" "width": "550px", --> You can specify pixels (px) or percent (%) "height": "333px" --> You can specify pixels (px) or percent (%) }, "hint": { "value": "Some hint" --> The hint shown in the lower left side of the dialog }, "filter": { --> If present, a filtering/search box will be rendered in the dialog header "placeholder": { "value": "Search" --> The default placeholder value that is shown in the filter box } } } } ] }
See Dialog and Sidebar Views - Archived.
The dialog iframe content is also responsible for handling events that originate from the dialog buttons or filter box:
Mostly likely you want to perform some action once the user presses "OK" or "Save" (or selects any of the secondary actions). You can register an event handler for every button by checking for its key (the one that you specified in the descriptor)
If you specify the primary action as:
Descriptor
1 2"primaryAction": { "name": { "value": "Yes" }, "key": "dialog.yes" },
You can then handle the click by using
Dialog
1 2function buttonClicked(event, closeDialog) { if (event.action === "dialog.yes") { // handle the action here } closeDialog(true); // you can also pass false if you want to prevent the dialog from closing (missing required fields, for instance) } AP.register({ "dialog-button-click": buttonClicked });
This works analogous to the button click handlers:
Dialog
1 2function filterChanged(event) { // filter your results here } AP.register({ "dialog-filter-changed": filterChanged });
These events are already debounced by the dialog implementation, so you will only receive an event 250ms after the user stopped typing in the filter box.
Note: Calls to AP.register
need to register for all events at once. Subsequent calls overwrite the registrations of the previous call. To listen for both button clicks and filter events, you would use:
1 2AP.register({ "dialog-button-click": buttonClicked, "dialog-filter-changed": filterChanged });
Declare the message action in the descriptor:
Descriptor
1 2"capabilities": { ..., "action": [ { "key": "myaddon-action-opendialog", "name": { "value": "Open dialog" }, "target": "myaddon-dialog", --> must match the key from the dialog "location": "hipchat.message.action" --> or hipchat.input.action } ] }
This will open a dialog, and in there an iframe in which HipChat will load the page from the URL specified in the dialog "url"
field.
You can also override the dialog options:
Descriptor
1 2"capabilities": { ..., "action": [ { "key": "message.reminder", "name": { "value": "Set Reminder" }, "location": "hipchat.message.action", "target": { "key": "message.reminder.dialog", "options": { "hint": "some other hint" } } } ] }
In the card description or in a notification message, you can link to a dialog by using the data-target
attribute:
1 2{ "style": "link", "id": "3422b9e1-ebbc-42af-8b06-5212fa8f3a01", "url": "http://example.com/example.png", "title": "Card Title", "description": { "format": "html", "value": "<a href='#' data-target='add-on-key:dialog-key'>Open Dialog</a>" }, "date": 1448348496130 }
Using the Javascript API, you can open a Dialog View from another View (e.g. from a Sidebar View):
View
1 2AP.require("dialog", function (dialog) { dialog.open({ key: "myaddon-dialog" // must match the key for the dialog }) });
You can override any options that you declared in the descriptor, by passing an additional options
parameter:
View
1 2var dialogOptions = { title: "My Dialog", options: { style: "warning", primaryAction: { name: "Yes", key: "dialog.yes", enabled: false }, secondaryActions: [ { name: "No", key: "dialog.no" } ], size: { width: "500px", height: "300px" }, hint: "Some hint", filter: { placeholder: "Search..." } } }; AP.require("dialog", function (dialog) { dialog.open({ key: "myaddon-dialog", // must match the key for the dialog options: dialogOptions }) });
The format of the options
parameter follows the format of the descriptor, but all the localizable elements as they appear in the descriptor are flattened:
1 2"name": { "value": "Yes" --> becomes --> "name": "Yes" }
In addition to specifying the look&feel options, you can also pass your own data to the dialog when you open it:
View
1 2AP.require("dialog", function (dialog) { dialog.open({ key: "myaddon-dialog" // must match the key for the dialog options: dialogOptions // as above parameters: { foo: "bar" // anything you want } }) });
Now the dialog iframe contents can receive your data by registering another event listener:
Dialog
1 2function receiveParameters(parameters) { // This function will receive the parameters that were used in dialog.open(...) if (parameters.foo === "bar") { // do something } } AP.register({ "receive-parameters": receiveParameters });
Dialogs can also update themselves. A typical example is changing the primary button enablement state depending on whether a user provided enough data.
Generally, all dialog attributes (besides key and url) can be updated dynamically by using the same format that we used to open a customized dialog above:
1 2AP.require("dialog", function(dialog) { dialog.update(dialogOptions); // dialogOptions look like the ones we used above to to open a custom dialog }); // For example: AP.require("dialog", function(dialog) { dialog.update({ title: "New Title", options: { size: { width: "700px", height: "500px" } } }); });
For the common case of updating the primary action, we provide a convenience method:
1 2AP.require("dialog", function(dialog) { dialog.updatePrimaryAction({ name: "New Label", // optional enabled: false // or true }) })
A dialog can also close itself by calling:
1 2AP.require("dialog", function(dialog) { dialog.close(); })
Rate this page: