Dialog.close()
dialog.close()
shouldn’t be used to return input from fields, it’s intended as a signaling mechanism only. This is because if the user presses ESC, dialog.close('reasonCanceled')
is called for you automatically, which means you’ll have a harder time differentiating between system-generated data and user-generated data. Instead, use dialog.close('ok')
(or similar) to indicate that the user is finished with the dialog.
Listening for form submission
Assume you’ve got something like this:
ourDialog = document.createElement("dialog");
ourDialog.innerHTML=`
<form>
<h1>Title</h1>
<hr />
<label>
<span>Button Width</span>
<input type="text" id="buttonwidth" />
</label>
<footer>
<button uxp-variant="primary" id="cancelbutton">Cancel</button>
<button uxp-variant="cta" id="okbutton">Set width</button>
</footer>
</form>
`;
document.body.appendChild(ourDialog); // <-- this is super important; without it the dialog will fail to show
Note: Just now realizing the docs don’t have document.body.appendChild(dialog);
for the non-react example. D’oh! We’ll fix that…
Now, to get a reference to the elements within, you can use dialog.querySelector
:
const form = ourDialog.querySelector("form");
const okButton = ourDialog.querySelector("#okbutton");
const cancelButton = ourDialog.querySelector("#cancelbutton");
There are several things at play when it comes to submitting forms:
- User presses ENTER
- User clicks the “ok” button (here, it’s “Set Width”)
- User clicks the “Cancel” button
- User presses ESC
Unless the user is already focused on a button, ENTER will raise form.onsubmit
. Pressing ENTER or clicking a button will raise that button’s onclick
event. And pressing ESC will call dialog.close('reasonCanceled')
.
There’s two things you need to be concerned with when responding to user input:
- closing the dialog and indicating user intent
- reading the dialog’s data to act on the user’s intent
The two should be kept fairly distinct – the result of dialog.showModal()
for example, should only ever deal with #1 – closing the dialog and indicating whether the user wants to proceed or cancel.
The second option can be handled after that point by reading the values of form elements in the dialogs.
(There’s a third step here – disposing of/reusing the dialog which I’ll skip for now.)
To handle #1, we need to wire up some event handlers:
form.onsubmit = function() {
evt.preventDefault(); // <-- otherwise, dialog.close() is called with nothing; will fix docs
ourDialog.close("ok");
}
okButton.onclick = function(evt) {
evt.preventDefault();
ourDialog.close("ok");
}
cancelButton.onclick = function() {
ourDialog.close("reasonCanceled");
}
This will now properly dismiss the dialog whatever the user clicks or presses.
Reading the user’s data
Dismissal is not the final goal, of course, so you need to get at the user’s data. We can do this pretty easily back where we call showModal
– the trick is to remember that the dialog itself and all its elements are still in the DOM:
return ourDialog.showModal()
.then(response => {
if (response === "ok") {
// user wants to set the button width
const buttonWidthElement = ourDialog.querySelector("#buttonwidth");
const buttonWidth = Number(buttonWidthElement.value);
// now we can do something with it
// for example:
selection.items[0].resize(buttonWidth, selection.items[0].height);
}
})
.catch(err => {
console.error(err.message);
});
Putting it all together
Here’s the final snippet, which should work for you (assuming you’ve got a manifest that has a menu pointing at showButtonWidthDialog
):
let ourDialog;
function showButtonWidthDialog(selection) {
if (!ourDialog) {
// the dialog has never been created before; create it now
ourDialog = document.createElement("dialog");
ourDialog.innerHTML = `
<form>
<h1>Title</h1>
<hr />
<label>
<span>Button Width</span>
<input type="text" id="buttonwidth" />
</label>
<footer>
<button uxp-variant="primary" id="cancelbutton">Cancel</button>
<button uxp-variant="cta" id="okbutton">Set width</button>
</footer>
</form>`;
document.body.appendChild(ourDialog);
}
// get references to the dialog
const form = ourDialog.querySelector("form");
const okButton = ourDialog.querySelector("#okbutton");
const cancelButton = ourDialog.querySelector("#cancelbutton");
// wire up our events
form.onsubmit = function(evt) {
evt.preventDefault();
ourDialog.close("ok");
}
okButton.onclick = function(evt) {
evt.preventDefault();
ourDialog.close("ok");
}
cancelButton.onclick = function() {
ourDialog.close("reasonCanceled");
}
// show the dialog (returning a promise), and handle the response
return ourDialog.showModal()
.then(response => {
if (response === "ok") {
// user wants to set the button width
const buttonWidthElement = ourDialog.querySelector("#buttonwidth");
const buttonWidth = Number(buttonWidthElement.value);
// now we can do something with it
// for example:
selection.items[0].resize(buttonWidth, selection.items[0].height);
}
})
.catch(err => {
console.error(err.message);
});
}
module.exports = {
commands: {
showButtonWidthDialog
}
}