I have a Blazor WebAssembly (.NET 6) application. I am using the MudBlazor component library.
I have a MudTextField
(text area) and MudFab
(button) like this:
<MudTextField T="string" Label="Message" Variant="Variant.Outlined" @bind-Value="@newMessage" Clearable="true" Lines="2" />
<MudFab Color="Color.Primary" StartIcon="@Icons.Material.Filled.Send" OnClick="@SendAsync" />
In the OnClick
event handler of the MudFab
(button), I am calling SendAsync
function, which looks like the following:
async Task SendAsync()
{
//some logic
await _client.SendMessageAsync(newMessage);
}
So user types text in MudTextField
. Then hits send button (MudFab), and SendAsync
method mentioned above gets executed. Everything so far works fine.
Now I want to add feature where user can press Ctrl + Enter key while typing message, and this should execute SendAsync
function. i.e, user does not have to use mouse and click send button (MudFab).
For this, I added following event handler in my code, and bound it to OnKeyDown
event. The code looks like this:
// notice 'OnKeyDown'
<MudTextField T="string" Label="Message" Variant="Variant.Outlined" @bind-Value="@newMessage" Clearable="true" Lines="2" OnKeyDown="HandleKeyDown"/>
<MudFab Color="Color.Primary" StartIcon="@Icons.Material.Filled.Send" OnClick="@SendAsync" />
....
private async Task HandleKeyDown(KeyboardEventArgs e)
{
if (e.CtrlKey && e.Key == "Enter")
{
await SendAsync();
}
}
Problem
This code only works if I place a breakpoint in the HandleKeyDown
method. Otherwise it doesn't work at all. I have been struggling for more than two days to make this simple logic work. What am I missing?
Things I have tried:
StateChanged()
after SendAsync()
, but did not work.MudTextField
to simple <input>
, and MudFab
to simple button
, but did not work.Last I tried doing it using jQuery as shown here, but it also had the same problem. It only worked if I place 'debugger;' in the on("keydown"...
function:
// this code is inside <script> tag:
$(document).ready(function () {
// Handle key press event
$(document).on("keydown", function (e) {
if (e.ctrlKey && e.key === "Enter") {
e.preventDefault(); /
//debugger; ------->> WORKS fine if I uncomment this
$("#btnChat_SendMessage").click();
console.log("pressed::ctrl-Enter::::::::::::::");
// tried Adding a slight delay
setTimeout(function () {
$("#btnChat_SendMessage").trigger("click");
}, 2000);
}
});
});
If I check browser console, I can see
pressed::ctrl-Enter::::::::::::::
printed on the console. It is printed as many times as I have hit Ctrl + Enter. But logic doesn't get executed.
If I run $("#btnChat_SendMessage").trigger("click");
directly on the browser console, the logic gets executed just fine.
Why is this happening? Can somebody please point out my mistake.
Thanks.
Use the KeyDownPreventDefault
property on MudTextField
to specify which keys need to be overriden. MudText docs
In the example below, a boolean field _preventDefault
is created to keep track of which keys to override. Then we call the SendAsync()
function only when the Ctrl+Enter 's are pressed.
<MudTextField T="string" @bind-Value="@_newMessage"
OnKeyDown="HandleOnKeyDown"
KeyDownPreventDefault="@_preventDefault"
Immediate="true"
Variant="Variant.Outlined" Clearable="true" Lines="2" Label="Message"/>
<MudFab Color="Color.Primary" StartIcon="@Icons.Material.Filled.Send" OnClick="@SendAsync" />
<h2>@_sendAsyncMessage</h2>
@code {
string _newMessage="";
bool _preventDefault = false;
string _sendAsyncMessage="";
public async Task HandleOnKeyDown(KeyboardEventArgs e)
{
if (e.Key == "Enter" && e.CtrlKey)
{
_preventDefault=true;
await SendAsync();
}
else{
_preventDefault=false;
}
}
async Task SendAsync()
{
_sendAsyncMessage = $"Sent message:{_newMessage}";
await Task.Delay(1000);
_sendAsyncMessage="";
}
}
Note I added Immediate="true"
property because the example relies on the _newMessage
being bound on each key press. Use/remove it according to your needs.