Home > Enterprise >  Creating a popup in Blazor using C# method
Creating a popup in Blazor using C# method

Time:04-26

I have a simple page index.razor with a button:

<a  @onclick="RedirectPage" >Log in</a>

<div
    @bind-Visible="@InvalidLogin"
    BodyText="Error">
</div>

@code{
    InvalidLogin {get; set;} = false;
}

Where the function RedirectPage checks if values are valid. If they are not, I want a popup giving information:

private void RedirectPage
{
    this.InvalidLogin = true;
}

This function is in the index.razor.cs and has been added with @using in the correct namespace.

How can I create it so that a popup shows up whenever the button is clicked?

CodePudding user response:

You can create a simple popup (or modal dialog) component. Below, I wrote a sample popup razor component using Bootstrap 5 toast component.

Popup.razor file

@{
    var showClass = IsVisible ? "d-block" : "d-none";
}

<div  data-bs-autohide="true" data-bs-delay="5000">
    <div  role="alert" aria-live="assertive" aria-atomic="true">
        <div >
            <strong >@HeaderText</strong>
            <button type="button"  aria-label="Close" @onclick="Close"></button>
        </div>

        <div >
            @BodyText
        </div>
    </div>
</div>

@code {
    [Parameter]
    public bool IsVisible { get; set; }

    [Parameter]
    public EventCallback<bool> IsVisibleChanged { get; set; }

    [Parameter]
    public string? HeaderText { get; set; }

    [Parameter]
    public string? BodyText { get; set; }

    public void Show(string bodyText, string headerText = "")
    {
        HeaderText = headerText;
        BodyText = bodyText;
        IsVisible = true;
        StateHasChanged();
    }

    private void Close()
    {
        HeaderText = string.Empty;
        BodyText = string.Empty;
        IsVisible = false;
        StateHasChanged();
    }
}

Using the Popup razor component in your code:

<a  @onclick="RedirectPage" >Log in</a>

<Popup @ref="popupRef" />

@code{
    private Popup popupRef;
    
    private void RedirectPage()
    {
        // Shows the popup at the center of the screen
        popupRef.Show("Popup body text");
    }
}

CodePudding user response:

How to create a dialog without a dependency on a third party library.

I had to use a minimal amount of js as the new HTML5 <dialog... element can only be opened in dialog mode with it .showModal() not by manipulating attributes.

wwwroot/scripts/dialogJsInteropt.js

export function showDialog(element, parm) {
    return element.showModal();
}

export function closeDialog(element, parm) {
    return element.close();
}

Dialog.razor

<CascadingValue Value=@this IsFixed=true >
    <dialog @ref="@dialogElement" @attributes=@CapturedAttributes>
    @if(visible)
    {
        @ChildContent
    }
    </dialog>
</CascadingValue>

Dialog.razor.cs

public partial class Dialog : ComponentBase, IAsyncDisposable
{
    private readonly Lazy<Task<IJSObjectReference>> moduleTask;
    private ElementReference dialogElement;
    private bool visible = false;

    public Dialog()
    {
        moduleTask = new(() => jsRuntime.InvokeAsync<IJSObjectReference>(
            identifier: "import",
            args: "./scripts/dialogJsInterop.js")
        .AsTask());
    }

    [Inject]
    private IJSRuntime jsRuntime { get; set; }

    [Parameter]
    public RenderFragment ChildContent { get; set; }

    [Parameter(CaptureUnmatchedValues = true)]
    public Dictionary<string, object> CapturedAttributes { get; set; }

    public async ValueTask ShowDialogAsync()
    {
        var module = await moduleTask.Value;
        await module.InvokeVoidAsync("showDialog", dialogElement);
        visible = true;
    }

    public async ValueTask CloseDialogAsync()
    {
        var module = await moduleTask.Value;
        await module.InvokeVoidAsync("closeDialog", dialogElement);
        visible = false;
    }

    public async ValueTask DisposeAsync()
    {
        if (moduleTask.IsValueCreated)
        {
            var module = await moduleTask.Value;
            await module.DisposeAsync();
        }
    }
}

A this stage you have a dialog that works.

I added the following components to make it more convenient. Note: I do use bootstrap from here forward for styling, this could be changed easily to tailwind for example.

DialogCloseButton.razor

<button @attributes=CapturedAttributes @onclick=@CloseDialog />

DialogCloseButton.razor.cs

public partial class DialogCloseButton : ComponentBase
{
    [CascadingParameter]
    public Dialog Dialog { get; set; }

    [Parameter(CaptureUnmatchedValues = true)]
    public Dictionary<string, object> CapturedAttributes { get; set; } = new Dictionary<string, object>
    {
        { "class", "btn btn-close" }
    };

    private async Task CloseDialog() => await Dialog.CloseDialogAsync();
}

DialogCloseButton.razor.css

.btn:focus {
    box-shadow: none;
}

DialogLayout.razor

<div >
    <div >
        @Header
    </div>
    <div >
        <DialogCloseButton />
    </div>
</div>
<div >
    @Content
</div>

DialogLayout.razor.cs

public partial class DialogLayout
{
    [Parameter]
    public RenderFragment Header { get; set; }

    [Parameter]
    public RenderFragment Content { get; set; }
}

Usage :

<Dialog @ref=@dialog >
    <DialogLayout>
        <Header>
           <MessagesIcon Size=16 /> Add Message
        </Header>
        <Content>
            <MessageFormView />
        </Content>
    </DialogLayout>
</Dialog>
<button  @onclick=@OpenDialog>Add Message</button>
@code {
    private Dialog dialog;

    ...

    private async Task OpenDialog() => await dialog.ShowDialogAsync();
}
  • Related