Search code examples
c#asp.net-corerazorrazor-pages

ASP.net-core Razor model binding list within with select


I am trying to get into asp.net core with razor pages. I use a database first approach for a database that I cannot modify. In the page I am working on I want to display a number of notions for which the user can select the score. Each notions has a different list of possibles scores that the user can choose from.

The Get is correct and the form correctly displays the selects with the items and the selection loaded from the database.

My problem is that when I try to post the form it is included in, the modelstate doesn't validates the score and the list of notions is empty.

I don't understand why the Notions list is empty at that states. Other properties works fine. Can anyone explain ?

Thanks in advance for your answers

My view

@foreach (var EvalComp_Notion in Model.Notions)
{
    <tr>
        <td>
            <select class="form-control" asp-for="@EvalComp_Notion.Note">
                @foreach (var choix in EvalComp_Notion.NotePossibles)
                {
                    <option class="form-control" value="@choix.Key">@choix.Value</option>
                }
            </select>
        </td>
    </tr>
}

And my pagemodel

[BindProperty]
public List<VM_Notion> Notions { get; set; } = new List<VM_Notion>();

public async Task<IActionResult> OnGetAsync(int? id)
{
    if (id == null) return NotFound();

    foreach(var ECN in EC.EvaluationCompetenceNotions)
    {
        Notions.Add(new VM_Notion()
        {
            Nom = ECN.Notion.Nom,
            Note = ECN.Note,
            Commentaire = ECN.Commentaire,
            NotePossibles = ECN.Notion.NotionEvalChoixes.Select(nec => new { Rg = nec.Rang, ch = nec.EvaluationChoix.Descr }).OrderBy(x => x.Rg).ToDictionary(ec => ec.Rg, ec => ec.ch)
        });
    }
// the notions list is correctly populated at this stage

    return Page();
}

public async Task<IActionResult> OnPostAsync()
{
    // the List<Notion> notions is empty here, so there is nothing to validates
    if (!ModelState.IsValid)
    {
        return Page();
    }

    // in here I should get the model and modify it according to the form's result

    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        
    }

    return Page();
}

public class VM_Notion
{
    public int Note { get; set; }
    [ValidateNever]
    public Dictionary<int, string?> NotePossibles { get; set; } = new Dictionary<int, string?>();
}

Solution

  • In the foreach loop , model binder cannot correctly bind the properties of list entities through the name as each is of the same name . Bind with for loop instead. The index will help binding the correct properties .

    <form method="post">
        <table>
            @for (int i = 0; i < Model.Notions.Count; i++)
            {
                <tr>
                    <td>
                        <select asp-for="@Model.Notions[i].Note" class="form-control">
                            @foreach (var choix in Model.Notions[i].NotePossibles)
                            {
                                <option class="form-control" value="@choix.Key">@choix.Value</option>
                            }
                        </select>
                    </td>
                </tr>
            }
        </table>
        <button type="submit" class="btn btn-primary">Submit2</button>
    </form>
    

    enter image description here