Show modal and non-modal dialogs in ASP.NET Core MVC and Blazor
Many web apps accept user input through dialog boxes. There are multiple
options when it comes to displaying a dialog box to the user. You can resort to
plain JavaScript or you can use some plug-in to accomplish the task. However, in
this article I am going to show a lesser known technique of displaying dialog
boxes. The HTML
<dialog> element can be used to display modal and non-modal dialog boxes. A
word of caution - <dialog> element is an experimental feature. The latest
versions of Chrome, Edge, and Firefox support it. But Firefox requires manual
enabling of this support (see later in this article). Go
here to check the browser compatibility. We will first use the
<dialog> element in MVC view file and then we will use it in a Blazor
WebAssembly application.
Brief introduction to <dialog> element
The <dialog> element is used to display modal and non-modal dialog boxes. It
offers three handy methods namely show(), showModal(), and close() that can be
used to show and close a dialog. The open property of the <dialog> element tells
you whether a dialog is already opened or not. The returnValue property can be
used to set the return value of the dialog. The close event can be handled to
trap the closing action on the dialog.
In its simplest form the <dialog> element can be used like this:
<dialog open>Hello World!</dialog>
And the outcome in Chrome is this:
Of course, in its current form we can't achieve anything meaningful other
than illustrating the simples usage of the dialog element.
So, let's create an ASP.NET Core MVC application and put the <dialog> element
to use with a dash of JavaScript code.
Using <dialog> in ASP.NET Core MVC
Begin by creating a new ASP.NET Core MVC web app as you normally do. We will
code the Index view as shown below:
Our Index view will look like this in the browser:
There are two buttons one for display the dialog in non-modal fashion and
other for displaying the dialog in modal fashion.
Clicking on the Show Dialog button displays the following dialog:
If you click on the Show Modal Dialog button the same dialog is displayed as
follows:
Notice the difference in the background of the two dialogs. Also, when the
dialog is shown in non-modal way you can interact with other parts of the page
but when the dialog is shown in modal way you can't interact with other parts of
the page unless you close the dialog.
Entering some name in the textbox and clicking on the OK button displays a
message below the buttons like this:
If you cancel the dialog it displays this message:
If you click on the Show Dialog button when the dialog is already open, it
shows this message:
Now that you know how the page and the dialog is going to work, let's add the
necessary markup and JavaScript code.
Open Index.cshtml file and add the following markup in it.
<button id="show">Show Dialog</button>
<button id="showModal">Show Modal Dialog</button>
<br /><br />
<h3 id="message"></h3>
<dialog id="dialog">
Enter your name :
<br /><br />
<input id="name" type="text" />
<br /><br />
<button id="ok" type="button">OK</button>
<button id="cancel" type="button">Cancel</button>
</dialog>
Notice the markup in bold letters. It uses the <dialog> element to wrap the
dialog content. The dialog consists of an <input> element and two <button>
elements.
Now let's add the JavaScript code. Begin by adding the following JS code at
the bottom of the page.
<script>
(function() {
// code here
})();
</script>
The code discussed below will go inside the function.
Firstly we will get hold of the various DOM elements that we need to work
with. This is done as follows:
var show = document.getElementById('show');
var showModal = document.getElementById('showModal');
var dialog = document.getElementById('dialog');
var message = document.getElementById('message');
var name = document.getElementById('name');
var yes = document.getElementById('ok');
var no = document.getElementById('cancel');
As you can see this code uses getElementById() method to grab various DOM
elements such as buttons, textbox, and the dialog.
Next, we will wire click event handlers of the Show Dialog and Show Modal
Dialog buttons.
show.addEventListener('click', function() {
if(!dialog.open)
{
dialog.show();
}
else
{
message.innerHTML = 'Dialog is already open!';
}
});
showModal.addEventListener('click', function() {
if(!dialog.open)
{
dialog.showModal();
}
else
{
message.innerHTML = 'Dialog is already open!';
}
});
The click event handler of Show Dialog button checks whether the dialog is
already opened or not using open property of the <dialog> element. If the open
property returns false we show the dialog using show() method. The show() method
displays the dialog in non-modal manner.
The click event handler of Show Modal Dialog uses showModal() method to
display the dialog in modal fashion.
Then we wire the click event handlers of the OK and Cancel buttons.
ok.addEventListener('click', function() {
dialog.close('OK');
});
cancel.addEventListener('click', function() {
dialog.close('Cancel');
});
Both these event handlers call close() method on the dialog in order to close
it. Note the parameter passed to the close() method. This value can be accessed
through the returnValue property of the dialog to figure out which button closed
the dialog.
Finally, add the event handler for the close event of the dialog element.
dialog.addEventListener('close', function() {
if(dialog.returnValue =='OK')
message.innerHTML = 'You entered : ' + name.value;
else
message.innerHTML = 'You cancelled the dialog';
});
The close event is raised when a dialog is closed by the user. Inside, we
check the returnValue property to decide whether the dialog was closed by
clicking the OK button or Cancel button. If the dialog was closed by clicking
the OK button we display the entered in the textbox in the message
element. Otherwise we tell the user that the dialog was cancelled.
You can run the application and check if it works as expected.
Using <dialog> in Blazor
In the preceding section you used the <dialog> element in ASP.NET Core MVC
application. How about using it in a Blazor WebAssembly application? You can do
so with the help of Blazor's JavaScript interop. If you aren't familiar with JS
interop I would suggest reading
this article before
going ahead.
Begin by creating a new Blazor WebAssembly app. Open the Index.razor
component and add this code:
@page "/"
@inject IJSRuntime JS
<button @onclick="OnShowDialog">Show Dialog</button>
<br /><br />
<h3>@Message</h3>
<dialog id="dialog">
Enter your name :
<br /><br />
<input id="name" type="text" @bind-value="@Name" />
<br /><br />
<button id="ok" type="button"
@onclick="OnOKClick">OK</button>
<button id="cancel" type="button"
@onclick="OnCancelClick">Cancel</button>
</dialog>
Here, we inject IJSRuntime object so that we can do JavaScript interop. The @onclick
event of the button is wired to the OnShowDialog() method. We will write this
method shortly. Then we output the Message property in <h3> element. The Message
property contains a message in the form of the name entered by the user or
cancellation message (see earlier section).
The <input> textbox is uses Blazor's two-way data binding through the
@bind-Value property. The Name property will added in the @code block later.
The click event of the OK and Cancel button is wired to two event handlers
namely OnOKClick() and OnCancelClick(). We will write these C# methods in the
@code block.
Next, add the @code block and write the Message and Name properties as shown
below:
public string Message { get; set; }
public string Name{ get; set; }
Then add the OnShowDialog() method that handles the click event of the Show
Dialog button.
public async void OnShowDialog()
{
var objRef = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync("ShowDialog", objRef);
this.StateHasChanged();
}
Here two important things happen. Firstly, we create a DotNetObjectReference
for passing it to the JS code. We then invoke ShowDialog() JavaScript function
that displays the dialog. We will write this JS function after completing the
@code block. The InvokeVoidAsync() method invokes the ShowDialog() method and
also passes the DotNetObjectReference to the client script.
Then write the OnOKClick() and OnCancelClick() methods as shown below:
public async void OnOKClick()
{
await JS.InvokeVoidAsync("CloseDialogOK");
this.StateHasChanged();
}
public async void OnCancelClick()
{
await JS.InvokeVoidAsync("CloseDialogCancel");
this.StateHasChanged();
}
These methods are quite straightforward and simply invoke CloseDialogOK() and
CloseDialogCancel() JavaScript functions respectively.
Finally, complete the @code block by adding the OnDialogClose() method as
shown below:
[JSInvokable]
public void OnDialogClose(string retValue)
{
if (retValue == "OK")
{
Message = "You entered : " + Name;
}
else
{
Message = "You cancelled the dialog";
}
this.StateHasChanged();
}
The OnDialogClose() method is decorated with [JSInvokable] attribute
indicating that it will be invoked from the JavaScript code. The JavaScript code
will trap the dialog's closing action and will invoke OnDialogClose() method by
passing the dialog's returnValue.
Inside, we display the Message as discussed earlier in the MVC example.
In the above code we used a few JavaScript functions such as ShowDialog(),
CloseDialogOK(), and CloseDialogCancel(). Now it's time to write these
functions.
Add a new JavaScript file named Javascript.js in the wwwroot folder of the
Blazor app. Then write the ShowDialog() function as shown below:
function ShowDialog(objRef) {
var dialog = document.getElementById('dialog');
dialog.addEventListener('close',
function () {
objRef.invokeMethodAsync("OnDialogClose",
dialog.returnValue).then(() => {
});
});
if (!dialog.open) {
dialog.showModal();
}
else {
alert('Dialog is already open!');
}
}
The ShowDialog() function accepts objRef parameter that is supplied using
DotNetObjectReference (see earlier discussion). Inside, it wires the close event
handler for the dialog and then displays the dialog using the showModal()
method. The close event handler invokes the OnDialogClose() C# method written in
the @code block. It also passes the returnValue to the OnDialogClose() method.
The CloseDialogOK() and CloseDialogCancel() functions are quite
straightforward and are shown below:
function CloseDialogOK() {
var dialog = document.getElementById('dialog');
dialog.close('OK');
}
function CloseDialogCancel() {
var dialog = document.getElementById('dialog');
dialog.close('Cancel');
}
These functions close the dialog by calling the close() method. They also
pass an appropriate returnValue to the close() method.
Now, open Index.html file from the wwwroot folder and add a <script>
reference to the JavaScript.js file (in <head> section) as shown below:
<script src="/JavaScript.js"></script>
Run the application to load the Index.razor component in the browser.
Click on the Show Dialog button to open the modal dialog.
Enter some name and click on the OK button.
Confirm the working of the Cancel button also.
Enabling <dialog> in Firefox
The <dialog> element is readily available in the latest versions of Chrome
and Edge. However, you need to explicitly enable it in Firefox. To do so, open
Firefox and type about:config in the address bar. This will open a page as shown
below. Now search for dialog and you should see dom.dialog_element.enabled
entry. Make sure to set its value to true.
That's it for now! Keep coding!!