Home    |    GitHub Page    |    API    |    FAQ

How to get feedback (user input) from a dialog?

I want to provide a dialog with an input box and get the entered value back to the plugin.
How can I do this with the current joplin.views.dialogs API?

My example command looks like this:

await joplin.commands.register({
  name: 'editURL',
  label: 'Set URL',
  iconName: 'fas fa-edit',
  enabledCondition: "oneNoteSelected && !inConflictFolder",
  execute: async () => {
    // get the selected note and exit if none is currently selected
    const selectedNote = await joplin.workspace.selectedNote();
    if (!selectedNote) return;

    // create new dialog
    // API: dialog box has fixed width which cannot be overwritten by plugin itself - so input is cutted
    const dialogs = joplin.views.dialogs;
    const urlDialog = await dialogs.create();
    await dialogs.setHtml(urlDialog, `
      <div class="joplin-note-ext-dialog" style="display:inline-flex; min-width:300px;">
        <label style="min-width:fit-content; margin:auto; padding-right:5px;">Set URL:</label>
        <input type="text" style="width:100%;" value="${selectedNote.source_url}">
      </div>
    `);
    const result = await dialogs.open(urlDialog);

    // get return and new URL value
    if (result == 'ok') {
      // API: How to get feedback from a dialog? PostMessage?
      alert('This button was clicked: ' + result);
    }
  },
});

Would it be possible to allow PostMessages like in joplin.views.panels API?
Or is there any other way to get this information from the dialog?

Addition: I think I found a small issue in the dialogs...

The opened dialog has a fixed width which cannot be overwritten by plugin content.
In the example command above, I want to have a min-width of 300px for the dialog. Just to a have a bigger input field.
But the dialog will not extend to the desired width. The input is just cutted at the end.

After adding width: fit-content; to the parent container div#joplin-plugin-content the dialog box extends to the desired width.

Hmm, yes good question, it seems I've overlooked that. How about making dialogs.open return the value of all form elements?

Other solutions indeed would involve postMessage, but that seems unnecessary as what you'd want from a dialog usually is the values of whatever fields are in it.

That would be great! This would increase the dialogs API a lot.

But how exactly would I have to imagine that? I mean how can I distinguish then between several inputs, selects or buttons?

The way I see it it would return a tree of keys/values for each form in the dialog.

So for this:

<form name="form1" action="/action_page.php">
	<label for="fname">First name:</label><br>
	<input type="text" id="fname" name="fname" value="John"><br>
	<label for="lname">Last name:</label><br>
	<input type="text" id="lname" name="lname" value="Doe"><br><br>
	<input type="submit" value="Submit">
</form> 

You'd get this (note how it takes the names from the input "name" property):

{
	form1: {
		fname: 'John',
		lname: 'Doe',
	},
}

If there are two forms, you might get this:

{
	form1: {
		fname: 'John',
		lname: 'Doe',
	},
	form2: {
		tel: '07777777',
		email: 'test@example.com',
	},
}

And for inputs that are not inside any form, it would put them under the global "_" key:

<label for="fname">First name:</label><br>
<input type="text" id="fname" name="fname" value="John"><br>
<label for="lname">Last name:</label><br>
<input type="text" id="lname" name="lname" value="Doe"><br><br>
<input type="submit" value="Submit">

Like this:

{
	_: {
		fname: 'John',
		lname: 'Doe',
	},
}

I think this way would cover any possible use case, since you can do relatively advanced dialog behaviour by modifying with JavaScript the input values. You can also use hidden inputs and have custom JS components modify its value.

1 Like

That looks perfect. I also think that it can be used to handle all use cases.

After small tests, it seems to work with the latest version 1.4.10.

I create the dialog now as follows:

await DIALOGS.setHtml(dialogEditURL, `
<div class="joplin-note-ext-dialog" style="display:inline-flex; min-width:300px;">
  <form name="urlForm">
    <label style="min-width:fit-content; margin:auto; padding-right:5px;">Set URL:</label>
    <input type="text" id="url" name="url" value="${selectedNote.source_url}" style="width:100%;">
  </form>
</div>
`);
const result = await DIALOGS.open(dialogEditURL);

With this I am able to retrieve the value from the input box with const newUrl = result.formData.urlForm.url as string;.

But there are still two problems I observed.

  1. I have to specify the form tag - the global value with '_' (as specified above) seems not to be created.

  2. When I hit Enter while the cursor is in the input box - the plugin HTML code is removed from the DOM completely. So only an empty div#joplin-plugin-content tag remains. The screenshot shows the dialog and the DOM after Enter was pressed:


    It seems this only happens, if a form is specified.

Yes in the end I've decided not to implement this because it's not really standard. In HML, inputs should be within form elements, so this is required by the plugin API too.

That's strange, I will check.