Search code examples
.netblazorblazor-component

Can I inherit a Blazor Component to add attributes?


Say I have a component MyComponent that prints out this HTML:

<my-component attr1="@(Attr1)"
              attr2="@(Attr2)"
              @attributes="@(AdditionalAttributes)">
    @(ChildContent)
</my-component>

Now I want to have MoreDetailedComponent that inherits MyComponent and declares Attr3. Can I reuse the above code somehow so I do not have to rewrite it (in reality there are tens of them):

@inherits MyComponent

<my-component attr1="@(Attr1)"
              attr2="@(Attr2)"
              attr3="@(Attr3)"
              @attributes="@(AdditionalAttributes)">
    @(ChildContent)
</my-component>

Solution

  • Turn out it's very simple, I just extend the AdditionalAttributes like this:

    // Non-extendable components
    public class DefaultMdComponent : ComponentBase
    {
    
        [Parameter(CaptureUnmatchedValues = true)]
        public IEnumerable<KeyValuePair<string, object>>? AdditionalAttributes { get; set; }
    
        [Parameter]
        public RenderFragment? ChildContent { get; set; }
        
    }
    
    // Extendable components should inherit this
    public class DefaultInheritableComponent : DefaultMdComponent
    {
    
        protected virtual IEnumerable<KeyValuePair<string, object>>? ProtectedAdditionalAttributes
            => null;
        
        protected IEnumerable<KeyValuePair<string, object>>? FinalAdditionalAttributes
        {
            get
            {
                if (AdditionalAttributes is null) { return ProtectedAdditionalAttributes; } 
                if (ProtectedAdditionalAttributes is null) { return AdditionalAttributes; }
    
                return AdditionalAttributes.Concat(ProtectedAdditionalAttributes);
            }
        }
    
    }
    

    MyComponent should prints it out like this:

    <my-component attr1="@(Attr1)"
                  attr2="@(Attr2)"
                  @attributes="@(FinalAdditionalAttributes)">
        @(ChildContent)
    </my-component>
    

    MoreDetailedComponent does not need its own Razor file but instead just override ProtectedAdditionalAttributes:

    public class MoreDetailedComponent : MyComponent
    {
    
        // ...
        
        protected override IEnumerable<KeyValuePair<string, object>>? ProtectedAdditionalAttributes => 
            new KeyValuePair<string, object>[] 
            {
                new("attr3", Attr3)
            };
    }