Home > Mobile >  Can you make abstract components in blazor
Can you make abstract components in blazor

Time:08-05

Blazor now seems to support some form of inheritance but there is no clear documentation around it abstract style components are possible.

For example lets say I want to be able to insert N number of <DynamicComponent> elements on a page, I need to be able to know up front what props they expose and how to fill them.

So I want to ideally force anyone making a component of this type to always have fields like:

@code {
   [Parameter] public abstract EventCallback OnSomeMandatoryEvent {get;}
   [Parameter] public abstract ISomeInterface Data {get;}
}

This way I know for sure the components I am wanting to pull in will always expose the required properties the convention requires.

So is this use case supported?

CodePudding user response:

This is how to implement interfaces in components.

Here are two interfaces:

public interface IActionComponent
{
    [Parameter] public EventCallback OnSomeMandatoryEvent { get; set; }
    [Parameter] public IBaseData? Data { get; set; }
}

public interface IBaseData
{
    Guid Uid { get; }
}

And three components - only two of which implement the interface:

// Component1.razor
@implements IActionComponent
<h3>Component1</h3>

@code {
    [Parameter] public EventCallback OnSomeMandatoryEvent { get; set; }
    [Parameter] public IBaseData? Data { get; set; }
}
// Component2.razor
@implements IActionComponent
<h3>Component2</h3>

@code {
    [Parameter] public EventCallback OnSomeMandatoryEvent { get; set; }
    [Parameter] public IBaseData? Data { get; set; }
}
// Component3.razor
<h3>Component3</h3>

@code {
    [Parameter] public EventCallback OnSomeMandatoryEvent { get; set; }
    [Parameter] public IBaseData? Data { get; set; }
}

And a test page:

@page "/"
@using System.Reflection

<h3>Dynamic Component Tester</h3>

@if (ComponentType is not null)
{
    <DynamicComponent Type=ComponentType />
}

<div>
    <input type="text" @bind-value=componentName />
    <button  @onclick=SetComponent>Add Component</button>
    <div >
        Types to enter are: Component1, Component2 or Component3
    </div>
</div>

@if (message != string.Empty)
{
    <div >
        @message
    </div>

}

@code {
    private Type? ComponentType;

    private string componentName = string.Empty;

    private string message = string.Empty;

    private void SetComponent()
    {
        message = string.Empty;
        var newType = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(t => t.Name == componentName);
        if (newType is not null)
        {
            var v = newType.GetInterface(typeof(IActionComponent).FullName ?? string.Empty);
            if (v is not null)
            {
                ComponentType = newType;
                return;
            }
            else
            {
                message = "Component does not implement IActionComponent";
                return;
            }
        }
        message = "Can't load the Component";
    }
}

CodePudding user response:

For anyone else who comes here looking for information on abstract classes for Blazor you can do the following:

public abstract class CustomElementComponent : ComponentBase
{    
    [Parameter]
    public EventCallback<string> SomeEvent { get; set; }

    [Parameter]
    public SomeModel Data { get; set; }

    protected override Task OnInitializedAsync()
    {
        // whatever
        return base.OnInitializedAsync();
    }
}

Then use it like so:

@inherits CustomElementComponent

<div >
  <label >Text To Show</label>
  <div >
    <input  type="text" @bind="Data.Text">
  </div>
</div>

@code {
    // All lifecycles from abstract class have been run and Data is available
}

I struggled to find any docs out around this specifically so while the interfaces above in the answer are good sometimes an abstract class will be what you need as you can hook into the lifecycle methods there too, allowing you to create conventions at base layers.

Its also worth noting you can also use generics on the abstract classes and add it to the consuming component like so @inherits CustomElementComponent<SomeType>

  • Related