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!!


Bipin Joshi is an independent software consultant, trainer, author, and meditation teacher. He has been programming, meditating, and teaching for 25+ years. He conducts instructor-led online training courses in ASP.NET family of technologies for individuals and small groups. He is a published author and has authored or co-authored books for Apress and Wrox press. Having embraced the Yoga way of life he also teaches Ajapa Yoga to interested individuals. To know more about him click here.

Get connected : Facebook  Twitter  LinkedIn  YouTube

Posted On : 03 November 2021


Tags : ASP.NET ASP.NET Core MVC .NET Framework C# Visual Studio