What's the recommended way of rendering a Blazor component dynamically?
Asked Answered
R

3

8

I am new to Blazor with basic Angular and Vue.js experience. I would like to render a list of polymorphic components:

<ul>
    @foreach (fruit of fruits) 
         <li>HOW DO I RENDER FRUIT HERE??? </li> // render the fruit component
</ul>

@code {
   // Each member in the list is a subtype of Fruit
   var fruits = List<FruitComponent> {
       new PearComponent(),
       new AppleComponent()'
       new BananaComponent(),
       new RasberryComponent()
}

From what I've gleaned, there's a few ways to achieve this, each with their own disadvantages. An uncommon one suggests using an undocumented API call, which could become deprecated without notice, but it appears to be almost ideal. Another suggests emitting markup in the code which brings back the tedium of writing ASP.NET Server Controls. Finally, the most common suggests using conditional markup, while very simple, it couples the rendering code to the components it is rendering.

Most of the documentation I've read could be stale and no longer pertinent. With the official release of Blazor, what's the recommended way to achieve this?

Retrogression answered 30/9, 2019 at 17:51 Comment(5)
What do you want on the ???? ?Vins
@HenkHolterman, I just want to render the fruitRetrogression
OK, I overlooked that Componet suffix. But how do you write those? Just classes with BuildRenderTree() or do you want to write a PearComponent.razor ? Because that doesn't rhyme with a ctor parameter afaik.Vins
@HenkHolterman. I want to render the component's razor file. I will modify the code. Yes, I wasn't aware you couldn't use a ctor. One of the issues I have with web frameworks is that they often force you to work around the language's built in OO facilies.Retrogression
learn.microsoft.com/en-us/aspnet/core/blazor/…Impediment
O
6

You have to create a RenderFragment, and use that as a renderer of your polymorphic component... I've used the default Blazor's template Counter component as a parent (CounterParent), and then the CounterChild inherits the CounterParent. I hope it helps!! Regards!

@page "/"

@foreach (CounterParent counter in components)
{
    RenderFragment renderFragment = (builder) => { builder.OpenComponent(0, counter.GetType()); builder.CloseComponent(); };
    <div>
        <div>Before the component</div>
        @renderFragment
        <div>Afterthe component</div>
    </div>
}

@code
{
    List<CounterParent> components = new List<CounterParent>() { new CounterParent(), new CounterChild() };
}
Overwhelm answered 2/10, 2019 at 0:45 Comment(2)
You're wecome! Where did you read that it isn't officially supported? It's a blazor's core concept afaik!Overwhelm
I'm using CSS Isolation in my component. The classes are not getting loaded.. Do you have any idea, how i can fix this?Bilabial
T
2

You could use a switch statement that checks the types. You can place components in each of the cases, or render your li however you like.

<ul>
    @foreach (fruit in fruits)
    {
        switch(fruit)
        {
            case PearComponent p:
                <PearComponent ParameterOfSomeSort="p"></PearComponent>
                <li>Or render pears like this, if you want the li in it</li>
                break;
            case AppleComponent a:
                <AppleComponent></AppleComponent>
                break;
            case BananaComponent b:
                <BananaComponent></BananaComponent>
                break;
            case RaspberryComponent r:
                <RaspberryComponent></RaspberryComponent>
                break;
        }
    }
</ul>
Team answered 30/9, 2019 at 19:31 Comment(1)
As I mentioned, this particular solution, while straightforward, is coupled to all of the ComponentFruit subtypes, instead of just the ComponentFruit. Consequently, you can't inject an unknown subtype of FruitComponent at runtime. It appears Team Blazor blundered on this one.Retrogression
C
0

In .NET 6 there is a third way:

<ul>
    @foreach (fruitType in fruitTypes)
    { 
        <li>
            <DynamicComponent Type="fruitType" /> 
        </li>
    }
</ul>
@code {
   // Each member in the list is a subtype of Fruit
   var fruitTypes = List<Type> {
       typeof(PearComponent),
       typeof(AppleComponent)'
       typeof(BananaComponent),
       typeof(RasberryComponent)
    };
}

You can even pass parameters to each component by using <DynamicComponent Type="typeof(Component)" Parameters="parameterDict" />, where parameterDict is of type Dictionary<string, object>.

More information about this can of course be found in the C# documentation.

Cao answered 28/8, 2024 at 7:37 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.