Blazor - How to create Components dynamically

前端 未结 2 1798
清酒与你
清酒与你 2020-12-06 04:44

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 foun

相关标签:
2条回答
  • 2020-12-06 05:29

    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

    0 讨论(0)
  • 2020-12-06 05:34

    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:

    mkArtakMSFT commented on 1 Oct 2019 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.

    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.

    0 讨论(0)
提交回复
热议问题