1

I'm trying out Blazor and I'm getting this exception when I'm trying to load a list of checkboxes using a for loop.

I've created the list here:

public List<Month> Months { get; set; }

protected override void OnInitialized()
        {
            List<Month> months = new List<Month>()
            {
                new Month{MonthId = 0, MonthName = "All Months", isMonthChecked = false},
                new Month{MonthId = 1, MonthName = "Jan", isMonthChecked = false},
                new Month{MonthId = 2, MonthName = "Feb", isMonthChecked = false},
                new Month{MonthId = 3, MonthName = "Mar", isMonthChecked = false},
                new Month{MonthId = 4, MonthName = "Apr", isMonthChecked = false},
                new Month{MonthId = 5, MonthName = "May", isMonthChecked = false},
                new Month{MonthId = 6, MonthName = "Jun", isMonthChecked = false},
                new Month{MonthId = 7, MonthName = "Jul", isMonthChecked = false},
                new Month{MonthId = 8, MonthName = "Aug", isMonthChecked = false},
                new Month{MonthId = 9, MonthName = "Sep", isMonthChecked = false},
                new Month{MonthId = 10, MonthName = "Oct", isMonthChecked = false},
                new Month{MonthId = 11, MonthName = "Nov", isMonthChecked = false},
                new Month{MonthId = 12, MonthName = "Dec", isMonthChecked = false}
            };
};

            Months = months.ToList();
            base.OnInitialized();

Then, I created the loop in the Blazor component:

@{ 
            for (int i = 0; i < @Months.Count(); i++)
            {
            <ul>
                <li><label for="@Months[i].MonthId" id="checkboxLabel">@Months[i].MonthName</label></li>
                <li><InputCheckbox id="@Months[i].MonthId" @bind-Value="@Months[i].isMonthChecked"></InputCheckbox></li>
            </ul>
            }
        }

I've stepped through the debugger and it is pulling the correct data, but when it finishes, it gives me the error. If I reduce the count to 12 (should be 13), it works. Not sure what is going on here.

5
  • try this: @Months.Count() - 1; Commented Nov 13, 2019 at 19:35
  • That prevents the exception, but it also removes the last month from the view. Commented Nov 13, 2019 at 19:38
  • I came up with a temporary fix, just added an additional field the end and just excluded it from the loop. Not the best practice, but it worked Commented Nov 13, 2019 at 19:53
  • asp.net is a little quirky with bools... and webassembly might be showing some kind of quirk here... just curious what happens when .isMonthChecked value is left out... still the same? The other thing that could possibly be exposing a bug is months to Months? case sensitivity quirk maybe? Commented Nov 13, 2019 at 20:06
  • Yeah I tried that as well, did the same. Wondering if it has something to do with Blazor because I've done this in MVC with no issue Commented Nov 13, 2019 at 20:20

2 Answers 2

7

You can solve it like this:

@for (int j = 0; j < Months.Count; j++)
{
    int i = j;  // a local copy to solve the capture problem

    <ul>
        <li><label for="@Months[i].MonthId" id="checkboxLabel">@Months[i].MonthName</label></li>
        <li><InputCheckbox id="@Months[i].MonthId" @bind-Value="@Months[i].isMonthChecked"></InputCheckbox></li>
    </ul>
}

Which means this is a new, Blazor specific variation on 'capturing the loop variable'.

When you look at the <pagename>.razor.g.cs file you can see that the checkbox requires two lambda's, here is a snippet:

 __value => Months[i].isMonthChecked = __value

and after the for-loop, when the RenderTree is being built, the value of i will be Count for all months.

Using Count()-1 in the original code (your temporary fix) will prevent the exception but note that the form will not function properly, the wrong month will be checked.

General conclusion: don't mix EditForm with a for-loop. foreach() is safe.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! That explains it!
This is still the working solution for this issue.
make sure you actually use the variable in the elements, otherwise the compiler can optimize the variable declaration away.
1

I prefer to use a foreach statement in this case :

@foreach(var month in _months)
{
    <ul>
        <li><label for="@month.MonthId">@month.MonthName</label></li>
        <li><InputCheckbox id="@month.MonthId" @bind-Value="@month.IsMonthChecked" /></li>
    </ul>
}

@code {
    private IEnumerable<Month> _months;

    protected override void OnInitialized()
    {
        _months = new List<Month>
        {
            new Month{ MonthId = 0, MonthName = "All Months", IsMonthChecked = false },
            new Month{ MonthId = 1, MonthName = "Jan", IsMonthChecked = false },
            new Month{ MonthId = 2, MonthName = "Feb", IsMonthChecked = false },
            new Month{ MonthId = 3, MonthName = "Mar", IsMonthChecked = false },
            new Month{ MonthId = 4, MonthName = "Apr", IsMonthChecked = false },
            new Month{ MonthId = 5, MonthName = "May", IsMonthChecked = false },
            new Month{ MonthId = 6, MonthName = "Jun", IsMonthChecked = false },
            new Month{ MonthId = 7, MonthName = "Jul", IsMonthChecked = false },
            new Month{ MonthId = 8, MonthName = "Aug", IsMonthChecked = false },
            new Month{ MonthId = 9, MonthName = "Sep", IsMonthChecked = false },
            new Month{ MonthId = 10, MonthName = "Oct", IsMonthChecked = false },
            new Month{ MonthId = 11, MonthName = "Nov", IsMonthChecked = false },
            new Month{ MonthId = 12, MonthName = "Dec", IsMonthChecked = false }
        };
        base.OnInitialized();
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.