7

I want to pass the int i into the button onclick function for each list item. I expected the "clickItem" function will receive 0..2 for correspondig list item. But it come out that it always receive 3 as argument. It seems that the variable i in the clickItem(i) is not evaluated at the time of render of the for loop. I have tried changing it to "clickItem(@i)" but it is still the same. What should I do? (I am using blazor server side, .net core 3 preview 5)

        @for (int i = 0; i < 3; i++)
        {
            <li> item @i <button onclick=@(() => clickItem(i))>Click</button> </li>
        }

enter image description here

Raymond Wong
  • 302
  • 1
  • 3
  • 9

3 Answers3

18

This is a classic problem, but slightly new in the context of Blazor.

You need to make a copy of i because otherwise the "lambda captures the loop variable". Capturing the copy is OK.

@for (int i = 0; i < 3; i++)
{
    int localCopy = i;
    <li> item @i <button onclick=@(() => clickItem(localCopy))>Click</button> </li>
}

Note that this is an issue with for() loops but not with foreach(), and only on the right hand side of a =>.

H H
  • 263,252
  • 30
  • 330
  • 514
  • Thanks Henk, it works. But I don't understand the underlying difference. Why the "copy" and "i" will be treated differently? Is there some reference for me to further study? – Raymond Wong Jun 03 '19 at 11:26
  • 1
    See my answer here for an explanation: https://stackoverflow.com/questions/55278600/calling-function-from-generated-button-in-blazor/55278788#55278788 – enet Jun 03 '19 at 11:32
  • 1
    You can google " lambda 'captures' the loop variable" for dozens of Q+A, mostly on SO. That's why I didn't make this answer too long. – H H Jun 03 '19 at 12:15
0

I tried this, and it worked. Hope it seems helpful to you.

 @foreach (var item in ListOfUser)
            {
                <tr>
                    <td>@item.FirstName</td>
                    <td>
                        <button @onclick="(() => GetDetail(item.UserId)) "> Click</button>
                    </td>
                </tr>
            }
maxwell
  • 3,788
  • 6
  • 26
  • 40
sami ullah
  • 925
  • 1
  • 9
  • 15
  • Yes a foreach() does not have the same problem as for(). But in the question, `i` is needed. – H H Aug 07 '22 at 07:45
0

If you want to use foreach loop instead, you can refer to the example below.

You declare a variable called index inside the loop which is used to store the index of the current item in the loop using the IndexOf method on the items list. This index is then passed as an argument to the clickItem function when the button is clicked.

@foreach (var item in items)
{
    var index = items.IndexOf(item);
    <li> item @item 
        <button onclick=@(() => clickItem(index))>Click</button>
    </li>
}
Ibrahim Timimi
  • 2,656
  • 5
  • 19
  • 31