Blazor - How to create Components dynamically

asp.net-core blazor c#

Question

I want to test if it was possible to create Blazor components dynamically.

I can't find any way to do this. I have experimented a bit with some dynamic content found on this link but have not ended up with any results.

1
7
5/11/2018 10:04:51 PM

Accepted Answer

For version 0.2 this is the answer from Steve Sanderson:

We'll implement nicer APIs to build RenderFragments in the future, but for now you can

@CreateDynamicComponent();
@functions {
    RenderFragment CreateDynamicComponent() => builder =>
    {
        builder.OpenComponent(0, typeof(SurveyPrompt));
        builder.AddAttribute(1, "Title", "Some title");
        builder.CloseComponent();
    };
}

Those are very low-level APIs (not even documented) so we hope not many people need to do this right now. Higher-level APIs for this will come later.

Found here

12
1/31/2020 8:57:28 AM

Popular Answer

Judging by the comments on the accepted answer and on the original version of this answer I think there may be a bit of confusion around dynamically adding components. There are (at least) a couple of ways to achieve this (and a number of existing questions on this, e.g. here). It all depends on exactly what you mean by 'dynamically':

1) Using conditional statements in your Razor code

If what you're trying to achieve is simply to show or hide components based on some state in your data or model, then the 'normal' way to render a component dynamically is to use some sort of conditional code in your Razor view.

Simple conditional rendering

@if (_showCounter)
{
  <MyCounterComponent Count="@_count" />
}

@code {
  bool _showCounter = true;
  int _count;
}

Simple repeating data sets

For repeating sets of data, such as lists of items you can take advantage of Blazor's data binding.

Take the example of a page/component that shows a sales order and then has a child component for each sales order line. You might have code that looks like this on your razor page:

  @foreach (var salesOrderLine in _salesOrder.salesOrderlines)
  {
    <SalesOrderLine SOLine=@salesOrderLine />
  };

If you had a button that added another sales order line then you could simply add the new record to the _salesOrder model/view model in that buttons click event. Button clicks normally trigger a re-render, so the page should then automatically show an extra SalesOrderLine component (and if it doesn't you can use this.StateHasChanged(); to tell it things are different and cause a re-render)

Repeating data sets containing different data types (possibly polymorphic)

If your list contains different types you can use a switch statement to decide which type of component to render, e.g. (from this github question):

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

2. Dynamic rendering using RenderFragment

There are some cases that can't be handled well using the Razor approach above. In those cases RenderFragment offers another way to dynamically render parts of a page.

Polymorphic lists

Where you have a truly polymorphic list (e.g. a list of objects that all implement the same interface or inherit from the same class) then this type of approach can be used (from this github post):

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

The Blazor team are considering improving how polymorphic lists are handled in Blazor

Conclusion

The key point here (for those from an MVC background) is that there's no need to try and manually inject the new HTML into the DOM, or dynamically load a partial view, in the way you might of in MVC, Blazor will do that for you.

Despite the similarity in syntax between razor pages for MVC and those for Blazor, the Blazor model is conceptually much closer to something like React than it is to MVC, it's really important to understand there's something along the lines of a shadow-DOM in the background.

This page has some good pointers on data binding in Blazor.



Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow