Parsa99
Parsa99

Reputation: 458

Blazor - What is the correct way to extend another component?

I'm using MudBlazor component library. In order to show loading on form buttons, the documentation guides like this:

<MudButton Disabled="@_processing" OnClick="ProcessSomething" Variant="Variant.Filled" Color="Color.Primary">
    @if (_processing)
    {
        <MudProgressCircular Class="ms-n1" Size="Size.Small" Indeterminate="true"/>
        <MudText Class="ms-2">Processing</MudText>
    }
    else
    {
        <MudText>Click me</MudText>
    }
</MudButton>

Now since I'm doing this a lot, I wanted to wrap this logic inside another component.

The following component does not do the job:

@inherits MudButton

@code {
    bool _loading;

    [Parameter]
    public bool Loading 
    {
        get => _loading;
        set
        {
            _loading = value;
            Disabled = value;
        }
    }

    [Parameter]
    public new RenderFragment ChildContent 
    {
        get => base.ChildContent;
        set => base.ChildContent = ExtendContent(value);
    }

    private RenderFragment ExtendContent(RenderFragment baseContent) => __builder =>
    {
        if (Loading)
        {
            <MudProgressCircular Class="ms-n2" Size="Size.Small" Indeterminate="true" />
        }
        @baseContent
    };
}

I get this error:

The type '<my_component>' declares more than one parameter matching the name 'childcontent'. Parameter names are case-insensitive and must be unique.

Upvotes: 4

Views: 2478

Answers (3)

Brian Parker
Brian Parker

Reputation: 14553

Create a component for the loading content:

ButtonLoadingContent.razor

@using MudBlazor
<MudProgressCircular Class="ms-n1" Size="Size.Small" Indeterminate="true" />
<MudText Class="ms-2">Processing</MudText>

BaseLoadingMudButton.cs

using MudBlazor;

public class BaseLoadingMudButton<TComponent> : MudButton
    where TComponent : ComponentBase
{
    protected override void OnParametersSet()
    {
        Disabled = Loading;

        if (Loading is true)
        {
            ChildContent = builder =>
            {
                builder.OpenComponent<TComponent>(sequence: 1);
                builder.CloseComponent();
            };
        }
        base.OnParametersSet();
    }

    [Parameter]
    public bool Loading { get; set; }
}

LoadingMudButton.cs

public class LoadingMudButton : BaseLoadingMudButton<ButtonLoadingContent> { }

Usage

<LoadingMudButton Loading=_processing OnClick="ProcessSomething" Variant="Variant.Filled" Color="Color.Primary">
    <MudText>Click me</MudText>
</LoadingMudButton>

enter image description here enter image description here

Why does it work? I didn't use .razor files for the inheritance. The base component does not have to use generics I included this to make it more flexible and as an example.

Upvotes: 5

buga
buga

Reputation: 1344

MudButton already has ChildContent Parameter, you don't need to inherit it, Just use it inside your new component, and redefine the parameters you need to pass them to the inner components

Upvotes: 0

MrC aka Shaun Curtis
MrC aka Shaun Curtis

Reputation: 30046

MudBlazor's component library inherits from ComponentBase which isn't really designed for Razor inheritance. You're trying to replace the ChildContent with your own markup.

You need to lift the markup stuff from the base component, hope there's no privates being used, and copy it into the child markup.

Here's my inherited component:

@inherits MudButton
@using MudBlazor.Extensions

<MudElement @bind-Ref="@_elementReference"
            HtmlTag="@HtmlTag"
            Class="@Classname"
            Style="@Style"
            @attributes="UserAttributes"
            @onclick="OnClickHandler"
            type="@ButtonType.ToDescriptionString()"
            href="@Href"
            target="@Target"
            rel="@(Target=="_blank"?"noopener":null)"
            disabled="@Disabled">

    <span class="mud-button-label">
        @if (!string.IsNullOrWhiteSpace(StartIcon))
        {
            <span class="@StartIconClass">
                <MudIcon Icon="@StartIcon" Size="@Size" Color="@IconColor" />
            </span>
        }

        @if (this.Loading)
        {
            <MudProgressCircular Class="ms-n1" Size="Size.Small" Indeterminate="true" />
            <MudText Class="ms-2">Processing</MudText>
        }
        else
        {
            <MudText>@ChildContent</MudText>
        }

        @if (!string.IsNullOrWhiteSpace(@EndIcon))
        {
            <span class="@EndIconClass">
                <MudIcon Icon="@EndIcon" Size="@Size" Color="@IconColor" />
            </span>
        }
    </span>

</MudElement>

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

The code comes from the MubBlazor Github repo here - https://github.com/MudBlazor/MudBlazor/blob/dev/src/MudBlazor/Components/Button/MudButton.razor.

My Demo Page:

@page "/"

<PageTitle>Index</PageTitle>

<MudText Typo="Typo.h3" GutterBottom="true">Hello, world!</MudText>
<MudText Class="mb-8">Welcome to your new app, powered by MudBlazor!</MudText>
<MudAlert Severity="Severity.Normal">You can find documentation and examples on our website here: <MudLink Href="https://mudblazor.com" Typo="Typo.body2" Color="Color.Inherit"><b>www.mudblazor.com</b></MudLink></MudAlert>

<MudText class="mt-6">

    <MudButton Disabled="@_processing" OnClick="ProcessSomething" Variant="Variant.Filled" Color="Color.Primary">
        @if (_processing)
        {
            <MudProgressCircular Class="ms-n1" Size="Size.Small" Indeterminate="true" />
            <MudText Class="ms-2">Processing</MudText>
        }
        else
        {
            <MudText>Click me</MudText>
        }
    </MudButton>

    <MyButton Loading=_processing Disabled="@_processing" OnClick="ProcessSomething" Variant="Variant.Filled" Color="Color.Primary">
        Hello
    </MyButton>

</MudText>
@code {
    private bool _processing;

    private async Task ProcessSomething()
    {
        _processing = true;
        await Task.Delay(5000);
        _processing = false;
    }
}

enter image description here

Upvotes: 0

Related Questions