I am learning the Blazor technology. I started a default increment project in VS 2019 and I have modified the code for Decrement with confirm() and alert but it does not work.
@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Increment</button>
<button class="btn btn-primary btn-danger" onclick="if (confirm('Are you sure to Decrement')) { @DecrementCount() }">Decrement</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
private void DecrementCount()
{
currentCount--;
// alert('Operation Successfully executed')
}
}
In my code snippet confirm() function works perfectly but I want to call a Decrement function is not working build failed. And I would like to add a success message in my function. Please provide any option instead of using confirm(),alert() functions.
A prompt box is often used if you want the user to input a value before entering a page. When a prompt box pops up, the user will have to click either "OK" or "Cancel" to proceed after entering an input value. If the user clicks "OK" the box returns the input value. If the user clicks "Cancel" the box returns null.
Blazor is a feature of ASP.NET, the popular web development framework that extends the . NET developer platform with tools and libraries for building web apps.
Unfortunately, there is not implementation of such useful functions in Blazor yet.
So you need to use JSRuntime
instance.
@inject IJSRuntime JsRuntime
...
@code
{
//...
await JsRuntime.InvokeVoidAsync("alert", "Warning!"); // Alert
bool confirmed = await JsRuntime.InvokeAsync<bool>("confirm", "Are you sure?"); // Confirm
string prompted = await JsRuntime.InvokeAsync<string>("prompt", "Take some input:"); // Prompt
//...
}
It makes possible to execute JS code right inside your C# code. With that you can use any JS logic you want to create behaviour you need.
See docs for details.
I am new to Blazor and a replacement for JavaScript Alert, Confirm, and Prompt was one of the first things on my list. I came up with a service in Blazor Server / BlazorWebView (I haven't tested in Web Assembly). The <Modal>
component we'll create can be controlled by the service or directly from JavaScript. Although, if you don't need to call the <Modal>
via JavaScript than you can remove any JavaScript or IJSRuntime
references.
The ModalService.cs
is very simple. It has an OnShow
event that we can hook into our <Modal>
component later. The event is a function that takes prameters ModalType, title, body and it returns a dynamic task.
Setup
ModalService.cs
namespace MyProjectName.Services
{
public class ModalService
{
public event Func<ModalBase.ModalType, string, string,Task<dynamic>> OnShow;
public async Task<dynamic> Show(ModalBase.ModalType mType, string title, string body)
{
if(OnShow != null)
return await OnShow?.Invoke(mType, title, body);
return null;
}
}
}
The ModalBase.cs
will be inherited by our <Modal>
component. It handles opening and closing the modal. Here is where we can also attach to the ModalService
event OnShow
and hook up support for JavaScript invoking.
ModalBase.cs
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
namespace MyProjectName.Services
{
public class ModalBase : ComponentBase, IDisposable
{
[Inject] ModalService ModalService { get; set; }
[Inject] IJSRuntime JS { get; set; }
public enum ModalType
{
Alert,
Prompt,
Confirm
}
protected override void OnInitialized()
{
// Attach to our service event.
ModalService.OnShow += Show;
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
// Set a JavaScript referene for our DotNet interop.
if(firstRender)
await JS.InvokeVoidAsync("MODAL.SetDotnetReference", DotNetObjectReference.Create(this));
}
public string Title { get; set; }
public string Body { get; set; }
public Guid Guid = Guid.NewGuid();
public string ModalDisplay = "none;";
public string ModalClass = "";
public bool ShowBackdrop = false;
public string PromptValue { get; set; }
private bool ConfirmValue { get; set; }
public ModalType MType { get; set; }
private List<string> MsgIds = new List<string>();
[JSInvokable("Show")]
public async Task<dynamic> Show(ModalType mType, string title, string body)
{
// The JavaScript call MODAL.DotNetReference.invokeMethodAsync is non-blocking
// This means multiple calls to show the modal using invokeMethodAsync will only show the modal once.
// We can solve this by making sure each message waits in line.
string msgId = Guid.NewGuid().ToString();
if (!MsgIds.Contains(msgId))
MsgIds.Add(msgId);
// If multiple messages are being processed, wait for this msgs turn.
while (MsgIds.Count > 1 && MsgIds.IndexOf(msgId) != 0)
await Task.Delay(250);
Title = title;
Body = body;
ModalDisplay = "block;";
ModalClass = "Show";
MType = mType;
ShowBackdrop = true;
StateHasChanged();
while (ShowBackdrop)
await Task.Delay(250);
switch (mType)
{
default:
case ModalType.Alert:
MsgIds.Remove(msgId);
return string.Empty;
case ModalType.Confirm:
bool confirmResponse = ConfirmValue;
MsgIds.Remove(msgId);
return confirmResponse;
case ModalType.Prompt:
string promptResponse = PromptValue;
MsgIds.Remove(msgId);
return promptResponse;
}
}
public void Close(bool isCancel)
{
// Determine returned values.
PromptValue = isCancel ? string.Empty : PromptValue;
ConfirmValue = isCancel ? false : true;
ModalDisplay = "none";
ModalClass = "";
ShowBackdrop = false;
StateHasChanged();
}
public void Dispose()
{
ModalService.OnShow -= Show;
}
}
}
I designed the <Modal>
component based off the bootstrap markup discussed here. The major difference is I that have moved the guts into ModalBase.cs
to interact with our service.
Modal.razor
@using Microsoft.JSInterop
@using MyProjectName.Services
@inherits ModalBase
<div class="modal @ModalClass" tabindex="-1" role="dialog" style="display:@ModalDisplay; overflow-y: auto;">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title w-100 text-center" style="padding-left:31px">@Title</h5>
<button type="button" class="close border-0 bg-white" data-dismiss="modal" aria-label="Close" @onclick="() => Close(true)">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body mx-auto text-center text-break">
@Body
@if (MType == ModalType.Prompt){
<input type="text" class="form-control text-center my-2" @bind-value="PromptValue" style="max-width:400px"></input>
}
</div>
<div class="modal-footer justify-content-center">
@if (MType == ModalType.Prompt || MType == ModalType.Confirm)
{
<button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => Close(false)">OK</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => Close(true)">Cancel</button>
}
else
{
<button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => Close(false)">Close</button>
}
</div>
</div>
</div>
</div>
@if (ShowBackdrop)
{
<div class="modal-backdrop fade show"></div>
}
Usage
Include the ModalService
into our service collection.
Program.cs
builder.Services.AddScoped<ModalService>();
MainLayout.razor
@using MyProjectName.Components
@inherits LayoutComponentBase
<PageTitle>My Project</PageTitle>
<Modal></Modal>
<div class="page">
.
.
.
</div>
Inject and use the service somewhere in your application.
Index.razor
@code
{
[Inject] public ModalService ModalService { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
if (await ModalService.Show(Modal.ModalType.Confirm,"Save Settings", "Are you sure you want to save settings?"))
{
string fileName = await ModalService.Show(Modal.ModalType.Prompt, "File Name", "Please enter a filename");
if (!string.IsNullOrEmpty(fileName))
await ModalService.Show(Modal.ModalType.Alert, "File Saved Success", $"File Saved as {fileName}");
else
await ModalService.Show(Modal.ModalType.Alert, "File Saved Cancelled", $"No file name was entered.");
}
}
// return base.OnAfterRenderAsync(firstRender);
}
}
JavaScript Usage
// Defined somewhere globally
var MODAL = {};
MODAL.DotNetReference = null;
MODAL.SetDotnetReference = function (pDotNetReference) {
MODAL.DotNetReference = pDotNetReference;
};
MODAL.MType = {
Alert: 0,
Prompt:1,
Confirm: 2,
};
// Called from wherever
MODAL.DotNetReference.invokeMethodAsync('Show', MODAL.MType.Prompt, `Title goes here`, `Body goes here`)
.then(data => {
console.log(`Prompt Response`, data);
});
JavaScript Note: Polyfil recommended for promise support in older browsers
Note: If you need to show the modal at earlier points in the application lifecycle, such as OnInitializedAsync
, than you'll need to change ServerPrerendered
to Server
.
@*<component type="typeof(App)" render-mode="ServerPrerendered" />*@
<component type="typeof(App)" render-mode="Server" />
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With