13

How to add a @ref to Blazor components inside a loop?

@for (int i = 0; i < 10; i++)
{
    <MyComponent @ref="???"/> // I want to add this component to the list
}

@code
{
    List<MyComponent> components = new List<MyComponent>();
}
Kahbazi
  • 14,331
  • 3
  • 45
  • 76

3 Answers3

21

My solution is as follows:

@for (int i = 0; i < 10; i++)
{ 
    <MyComponent @ref="ComponentRef" />
}

@code {
    List<MyComponent> ComponentRefs = new List<MyComponent>();
    MyComponent ComponentRef {
        set { ComponentRefs.Add(value); }
    }
}

Explanation

Jim G.
  • 15,141
  • 22
  • 103
  • 166
  • 2
    Yes, this works too. Check the obj folder and find MyComponent.razor.g.s.You will see `__value` in the generated code there. – Kahbazi Feb 05 '20 at 20:15
  • 3
    The problem with this is that there is no process to remove items from the ComponentsRefs list if the contents of the for loop change. – Christopher Edwards Nov 30 '21 at 19:59
  • I'm still looking for a solution for this, especially variable length arrays/lists. For fixed size this works: https://stackoverflow.com/questions/58205090/using-ref-inside-for-loop-to-get-element-reference. Ironically, I had the same idea but i deem it perverse (or Blazor that is). @ref=item[i] does behave like a lambda and will not work unless capturing `i` locally, but using a single Property and misusing the setter works. OMG! The real problem is, where/when are the refs ACTUALLY assigned. IDK of any method to access this. `BuildRenderTree` executes more often. `OnRenderAsync` also. – somedotnetguy Aug 15 '22 at 17:45
  • @ChristopherEdwards: What do you mean "loop changed"? – Jim G. Feb 28 '23 at 13:37
4

The way that Blazor compiler works now, you can inject C#code on @ref attribute. You can use it for adding the components to a list.

@for (int i = 0; i < 10; i++)
{
    <MyComponent @ref="components.Add((MyComponent)__value);//" />
}

@code
{
    List<MyComponent> components = new List<MyComponent>();
}
Kahbazi
  • 14,331
  • 3
  • 45
  • 76
  • 3
    Where does this __value come from? "The name '__value' does not exist in the current context" – Swimburger Aug 13 '20 at 16:59
  • 3
    Could it be that this somehow was deprecated with a newer version? I can't even find `__value` in the razor.g.cs file mentioned in another comment. But all in all I'd rather choose not to use this anyway even if I'd find out how. It uses the generated code an is even more subject to change. So I really don't want to rely on this solution – Manuel Zelenka Nov 19 '20 at 18:41
  • 4
    answer seems to be completely incorrect. I get a compiler error that @ref must be a property or variable assignment – user1029883 Mar 29 '22 at 14:58
  • 1
    As of writing this comment, this approach does not work. – Lucas Jan 24 '23 at 06:31
  • @Lucas: Did you try this? https://stackoverflow.com/a/60083369/109941 – Jim G. Feb 28 '23 at 13:36
4

As the above did not work I found one simple solution. Add the component to an internal list on the ref setter. You can then reference the component via the index.

Example:

private List<MyComponent> components = new List<MyComponent>>();

        public MyComponent MyComponentRef
        {
            get
            {
                return null;
            }
            set
            {
                components .Add(value);
            }
        }
Jim G.
  • 15,141
  • 22
  • 103
  • 166
user1029883
  • 695
  • 7
  • 21