TiGreX
TiGreX

Reputation: 1816

add list of dynamic components in blazor

I just started to have a look in blazor (v0.3) and doing some test I wanted to add a list using blazor

First I created a List<string> to test a simple list in the same page

<ul>
    @foreach (var item in listItems)
    {
        <li>@item</li>
    }
</ul>


@functions {

    private List<string> listItems = new List<string>();
    private string newItem;

    private void AddItem()
    {
        if (string.IsNullOrEmpty(newItem))
            return;

        listItems.Add(newItem);
        newItem = "";
    }

}

this is working fine, is adding every element to the list when I add it. but then, i tried to add components, add a single component was easy, based on this question here but for a list I had the next problem:

<li id="@ID">
    @Text
</li>   




@functions {
  [Parameter]
  string Text { get; set; } 
  [Parameter]
  string ID { get; set; }
}
<input type="text" bind="TxtExample" name="inpAdd"/>
  <button onclick="@addCompoment">add comp1</button>
<div class="simple-list-list">
    @if (!componentListTest.Any())
    {
        <p>You have no items in your list</p>
    }
    else
    {
        <ul>
            @foreach (var item in componentListTest)
            {
                @item
            }
        </ul>
    }
</div>

@functions {

    private List<RenderFragment> componentListTest { get; set; }
    private int currentCount {get; set;}
    private string TxtExample { get; set; }

    protected override void OnInit()
    {
        currentCount = 0;
        componentListTest = new List<RenderFragment>();
    }


    protected void addCompoment()
    {

        componentListTest.Add(CreateDynamicComponent(currentCount));
        currentCount++;
    }


    RenderFragment CreateDynamicComponent(int counter) => builder =>
    {
        var seq = 0;
        builder.OpenComponent(seq, typeof(listExample));
        builder.AddAttribute(++seq, "Text", "text --  "+TxtExample);
        builder.AddAttribute(++seq, "id","listed-"+counter);

        builder.CloseComponent();

    };
}

when I load the fist element is loaded correctly: enter image description here

but when I entered the second one, all of them are replaced for the last one:

enter image description here

Any idea whats going on?

Upvotes: 6

Views: 16438

Answers (2)

Dan Friedman
Dan Friedman

Reputation: 5218

This is because TxtExample is global to the component. When Blazor detects a potential UI change, it recalculates the entire component and updates the DOM with any differences. So when you change the textbox, TxtExample is updated and then the Razor is recalculating, inserting the new value of TxtExample for all rows.

Upvotes: 0

Flores
Flores

Reputation: 8932

You are making it too complicated. You don't need to dynamically instantiate components for this scenario to work.

You can just do a:

<ul>
    @foreach (var item in listItems)
    {
        <myComponent bind-myVar="@item"></myComponent>
    }
</ul>

And the components will be instantiated for you.

Also see here how to make the parameters work on your component.

Upvotes: 5

Related Questions