I have the below code but the index parameter that is passed when I click the <tr>
element is always 9.
That is becuase I have 9 rows in the table that is passed to the component as data. So looks like the index is always the value of variable 'i' which was last set... in this case the value of i after the last row in foreach loop is 9 so i am getting the index parameter as 9 on clicking all the rows in the table...
What is the issue in my code which is not setting the i
value for each row onclick.
<table border="1">
@for(int i=0;i< ListData.DataView.Table.Rows.Count; i++)
{
<tr @onclick="(() => RowSelect(i))">
@foreach (ModelColumn col in ListData.ListColumns)
{
<td>@ListData.DataView.Table.Rows[i][col.Name]</td>
}
</tr>
}
</table>
@code {
private async Task RowSelect(int rowIndex)
{
await ListRowSelected.InvokeAsync(rowIndex);
}
}
Actually your problem is about lambda that captures local variable. See the following simulation with a console application for the sake of simplicity.
class Program
{
static void Main(string[] args)
{
Action[] acts = new Action[3];
for (int i = 0; i < 3; i++)
acts[i] = (() => Job(i));
foreach (var act in acts) act?.Invoke();
}
static void Job(int i) => Console.WriteLine(i);
}
It will output 3, 3, 3
thrice rather than 0, 1, 2
.
Quoted from the official documentation about EventCallback:
<h2>@message</h2>
@for (var i = 1; i < 4; i++)
{
var buttonNumber = i;
<button class="btn btn-primary"
@onclick="@(e => UpdateHeading(e, buttonNumber))">
Button #@i
</button>
}
@code {
private string message = "Select a button to learn its position.";
private void UpdateHeading(MouseEventArgs e, int buttonNumber)
{
message = $"You selected Button #{buttonNumber} at " +
$"mouse position: {e.ClientX} X {e.ClientY}.";
}
}
Do not use a loop variable directly in a lambda expression, such as
i
in the preceding for loop example. Otherwise, the same variable is used by all lambda expressions, which results in use of the same value in all lambdas. Always capture the variable's value in a local variable and then use it. In the preceding example, the loop variable i is assigned tobuttonNumber
.
So you need to make a local copy for i
as follows.
@for(int i=0;i< ListData.DataView.Table.Rows.Count; i++)
{
int buffer=i;
<tr @onclick="(() => RowSelect(buffer))">
@foreach (ModelColumn col in ListData.ListColumns)
{
<td>@ListData.DataView.Table.Rows[i][col.Name]</td>
}
</tr>
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With