How to use alert(),confirm() and prompt() function using Blazor?
Asked Answered
M

2

50

I'm 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.

Minimum answered 20/3, 2020 at 11:26 Comment(0)
A
96

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.

Amsterdam answered 20/3, 2020 at 11:36 Comment(5)
For Blazor users with no former JavaScript knowledge: Besides confirm(), JavaScript also offers the methods alert() to show a message and a OK button and prompt() (which asks the user to input some text).Anaclinal
So this is simple and functional; however, I find that it lacks the finesse and flexibility of SweetAlert2. Isn't there a way to accomplish SweetAlert without JavaScript?Kindness
@JayImerman i think you should create separete question about thatAmsterdam
I found the CurrieTechnologies NuGet package for SweetAlert. That did the trick.Kindness
For beginners like me, I found that the code should be wrapped in a method. For me, I used the OnInitializedAsync()Wallasey
E
2

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">&times;</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" />
Ere answered 12/5, 2022 at 17:36 Comment(1)
More information about calling the modal from Javascript can be found here https://mcmap.net/q/352120/-how-to-use-bootstrap-modal-in-blazor-client-appEre

© 2022 - 2024 — McMap. All rights reserved.