Is there any guidance on how to make the ESC
key close the currently-opened dialog, by chance?
Hi @DragonSpark,
You can close the currently open dialog by invoking the Close method of the DialogService. Then you can handle some of the keyboard events.
Alright, I finally got this working. Note that this wasn't as simple as applying onkeypress
and calling it a day. In order for the key press event to fire, a child component within the container that has the event applied to it must be focused.
Easier said than done.
This is what I ended up making with a Confirm.razor
:
@inject DialogService Dialogs
@inherits RadzenComponent
<RadzenCard Style="padding: 20px;" @onkeyup="LogKeyPressed">
<p Style="margin-bottom: 10px;">@Content</p>
<div class="row">
<div class="col-md-12">
<RadzenButton Text="Ok" Click="Accept" Style="margin-bottom: 10px; width: 150px" />
<RadzenButton id="@UniqueID" Text="Cancel" Click="Cancel" ButtonStyle="ButtonStyle.Secondary"
Style="margin-bottom: 10px; width: 150px" />
</div>
</div>
<Evaluate>document.getElementById("@UniqueID").focus();</Evaluate>
</RadzenCard>
@code {
protected override void OnInitialized()
{
base.OnInitialized();
Cancel = Cancel.HasDelegate ? Cancel : EventCallback.Factory.Create<MouseEventArgs>(this, _ => Dialogs.Close());
}
[Parameter]
public string Content { get; set; }
[Parameter]
public EventCallback<MouseEventArgs> Accept { get; set; }
[Parameter]
public EventCallback<MouseEventArgs> Cancel { get; set; }
void LogKeyPressed(KeyboardEventArgs eventArgs)
{
switch (eventArgs.Code)
{
case "Escape":
Dialogs.Close();
break;
}
}
}
Note the use of UniqueId
. I would prefer to be able to emit this from the cancel button but the property is protected
and there doesn't seem to be an obvious way of emitting it.
Additionally, note the use of the Evaluate
tag. That is found here defined as an Evaluate.razor
file:
@using Microsoft.JSInterop
@inject IJSRuntime JSRuntime;
@code {
// ATTRIBUTION: https://github.com/dotnet/aspnetcore/issues/16218#issuecomment-552052798
[Parameter]
public RenderFragment ChildContent { get; set; }
[Parameter]
public string Type { get; set; } = "text/javascript";
protected override bool ShouldRender() => false; // important!!
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
if (firstRender && ChildContent != null && Type == "text/javascript")
{
var script = ChildContent.Text();
if (!string.IsNullOrWhiteSpace(script))
{
await JSRuntime.InvokeVoidAsync("eval", script);
}
}
}
}
Also worth noting that I tried to make use of the autofocus
attribute but that did not seem to make a difference or work in this scenario.
So, not very straight-forward and it might be due to my novice-level knowledge of Blazor. Hopefully it will help someone else who encounters the same issue.
I would, of course, appreciate any obvious improvements and/or suggestions to my approach here to simplify the amount of work needed here to do a such a simple perceived behavior.
EDIT: Naturally, after posting I realized I didn't provide the actual use of the Confirm
dialog. Here that is, in the form of an EventCallback
:
Task ConfirmDelete(EntryView view)
=> Dialogs.OpenAsync("Delete Entry",
ds => @<Confirm Content="Are you sure you'd like to delete this entry?" Accept="() => Confirm(view.Id)"/>,
new DialogOptions {Width = "unset"});
Where Confirm(Guid)
(not shown) actually deletes from model.