Call method in component

Viewed 2558

I have this "Alert" component:

@if (Show)
{
    <div class="alert @Class" role="alert">
        @Text
    </div>
}

@functions
{
    [Parameter]
    private bool Show { get; set; } = false;

    [Parameter]
    private string Text { get; set; } = String.Empty;

    [Parameter]
    private string Class { get; set; } = String.Empty; //Success, Warning etc.
}

However, when I call this component on my page I still need to create atleast two variables - ShowError and ErrorText - to handle the state of this alert still clutters my code a lot as this alert exists on practically all pages.

My question is: Is it possible to de-clutter the code by calling a ShowMessage method in the child component?

An example would be something like this:

Page

@page "/my-page"
@inject HttpClient Http


<!-- A lot of HTML code here -->

<Alert/>

<!-- A lot of HTML code here -->


@functions {

    protected override async Task OnInitAsync()
    {
        var response = await Http.PostJsonAsync<Response>("/api/sessions/create", null);
        if (response.StatusCode == HttpStatusCode.OK)
        {

        }
        else
        {
            myAlertComponent.ShowSuccessMessage(response.Message);
        }
    }
}

"Alert" component

@if (Show)
{
    <div class="alert @Class" role="alert">
    @Text
    </div>
}

@functions
{
    [Parameter]
    private bool Show { get; set; } = false;

    [Parameter]
    private string Text { get; set; } = String.Empty;

    [Parameter]
    private string Class { get; set; } = String.Empty; //Success, Warning, Danger

    public void HideAlerts()
    {
    Show = false;
    }

    public void ShowSuccessMessage(string message)
    {
    Show = true;
    Text = message;
    Class = "success":
    }

    public void ShowErrorMessage(string message)
    {
    Show = true;
    Text = message;
    Class = "danger":
    }
}
1 Answers

To call component methods try adding a reference to the component with @ref and then adding the component declaration in the @code block. If the methods are public in the component you can use them outside of the component's scope.

Parent.razor

<Alert @ref="Alert" Text="I am showing" /> @*Notice the @ref tag;*@
<button @onclick="() => ShowAlert(true)">Show Success</button>
<button @onclick="() => ShowAlert(false)">Show Failure</button>
<button @onclick="HideAlert">Hide</button>

@code {
    private Alert Alert { get; set; } // This is where the @ref is bound; no need to initialize, the markup does that for you.

    private void ShowAlert(bool success)
    {
        if (success) Alert.ShowSuccessMessage("Success!!");
        else Alert.ShowErrorMessage("Failed :(");
    }
    private void HideAlert() => Alert.Hide();
}

Alert.razor

@if (_show)
{
    <div class="alert alert-@_class" role="alert">
        <strong>@Text</strong>
    </div>
}

@code
{
    [Parameter] public string Text { get; set; } = string.Empty; // set as "I am showing", but will be updated if a message is passed to the show methods below

    private bool _show { get; set; }
    private string _class { get; set; } = string.Empty;

    public void Hide() { _show = false; StateHasChanged(); }

    public void ShowSuccessMessage(string message? = null)
    {
        _show = true;
        Text = message ?? Text ?? string.Empty;
        _class = "success";
        StateHasChanged(); // StateHasChanged() informs the parent component that the child has updated and to update the dom
    }

    public void ShowErrorMessage(string? message = null)
    {
        _show = true;
        Text = message ?? Text ?? string.Empty;
        _class = "danger";
        StateHasChanged();
    }
}

See Section: Capture references to components

Related