Aspnetcore: Does Blazor support dynamic rendering of polymorphic components?

Created on 1 Oct 2019  路  2Comments  路  Source: dotnet/aspnetcore

I've been trying to render a list of components dynamically as demonstrated below:

<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()
}

So far, I can't find a straight answer officially or unofficially on how to do this. Given the rapid rate of changes, it's difficult to know whether the suggestions I found are even relevant anymore.

The most common method suggested is to use conditional markup to determine the component's type and declare the appropriate tag:

<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>

While workable, the code is tightly coupled to the FruitComponent subtypes. Consequently, you can't render a new subtype without code modification. I'll spare you the details of the other approach which emits markup from the code behind. I rather not go back to the old days of ASP.NET Forms Server Control development.

Does Blazor even support this as a first class citizen? It's hard to believe it doesn't as it is a very common use case, especially when DI is baked into dotnetcore. Is there a way to do this, preferably in a declarative way as Vue.js does?

area-blazor question

Most helpful comment

This is the solution I came to

@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() };
}

I posted it in stackoverflow, but I share it here maybe for future reference.
Regards!

All 2 comments

Thanks for contacting us, @Joebeazelman.
Using the switch approach you have will be our recommendation. We will consider doing something better in this area in the future.

This is the solution I came to

@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() };
}

I posted it in stackoverflow, but I share it here maybe for future reference.
Regards!

Was this page helpful?
0 / 5 - 0 ratings