How can I bind complex Lists in ASP.NET Core RazorPages
The key to complex object binding is ensuring that a sequential index in square brackets is added to the form field's name attribute e.g [0].IsSelected
or Positions[0].IsSelected
in your case. You can output the correct HTML using a for
loop and tag helpers quite easily.
You can read more about the principal here: https://www.learnrazorpages.com/razor-pages/model-binding#binding-complex-collections. Then you should be able to apply it to your application.
Jonas
Updated on July 20, 2022Comments
-
Jonas almost 2 years
I'm new to ASP.NET Core Razor Pages. I try to retrieve a List<> from a Page via POST. If I bind primitive Data types, I didn't face any problems. However, If I want to pass data from my Page to the Server, which contains a List I got trouble. I was able to pass the data from the server to the client, but not back.
This is an extract from my Code:
The RazorPage:
<form method="post"> <table class="table"> <thead> <tr> <th> @Html.DisplayNameFor(model => model.Positions[0].Number) </th> <th> @Html.DisplayNameFor(model => model.Positions[0].IsSelected) </th> </tr> </thead> <tbody> @if (!(Model.Positions is null)) { @foreach (var item in Model.Positions) { <tr> <td> @Html.DisplayFor(modelItem => item.Number) </td> <td> @Html.CheckBoxFor(modelItem => item.IsSelected) </td> </tr> } } </tbody> </table> <input type="submit" />
The Backend C#-file:
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; using Project.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.EntityFrameworkCore; namespace Project.Pages { public class TestModel : PageModel { private readonly DBContext _context; [FromRoute] public int? Id { get; set; } public List<SelectListItem> CustomerOrder { get; set; } = new List<SelectListItem>(); [BindProperty] public string SelectedNumber { get; set; } [BindProperty] public List<Position> Positions { get; set; } public TestModel(Project.Models.DBContext context) { _context = context; } public void OnGet() { if (!(Id is null)) { _context.CustomerOrder.Select(co => co.OrderNumber).Distinct().ToList().ForEach(y => CustomerOrder.Add(new SelectListItem(text: y, value: y))); } } public async Task OnPostAsync() { if (!(SelectedNumber is null)) { string s = $@" select * from Table1 xyz where xyz.Column1 in ( SELECT distinct Column1 FROM Table1 where value = '" + SelectedNumber + "') and xyz.name = 'SLLZ'"; var res = await _context.Table1.FromSql(s).Select(x => x.ValueDescription).Distinct().OrderBy(x => x).ToListAsync(); Positions = new List<Position>(); foreach (var item in res) { Positions.Add(new Position { Number = item }); } } _context.CustomerOrder.Select(co => co.OrderNumber).Distinct().ToList().ForEach(y => CustomerOrder.Add(new SelectListItem(text: y, value: y))); } } public class Position { public string Number { get; set; } public bool IsSelected { get; set; } } }
If I set a Breakpoint at the beginning of the OnPost-Method, I would expect the List to be filled with the IsSelected-Property related to the user's input in the checkbox, but it isn't.