2
votes

In my razor page PageModel I have a bound List<T> property:

[BindProperty]
public List<JobCard> CustomerSpecificJobCards { get; set; }

Here is the JobCard model:

public partial class JobCard
{
    public int JobCardId { get; set; }
    public string Products { get; set; }
    public string CusCode { get; set; }
    public string Category { get; set; }
    public bool IsAssigned { get; set; }
}

The list of JobCards is populated after the user posts an order number from the page:

CustomerSpecificJobCards = AllJobCards.Where(jc => jc.CusCode == WorkOrderInfo.MarkForCusCode).ToList();

It is then displayed in a form on the razor page via a foreach loop:

@foreach (var card in Model.CustomerSpecificJobCards)
{
    <div class="col-1"><input asp-for="@card.IsAssigned" /></div>
    <div class="col-9">@card.Products</div>
    <div class="col-2">@card.JobCardId</div>
}

Users are shown a list of job cards and a checkbox. Once checked the user submits the selections. When I look at the CustomerSpecificJobCards that are posted, the list is empty. Why? Based on information here, I decided to change the foreach loop to a for loop:

@for (var card = 0; card < Model.CustomerSpecificJobCards.Count; card++)
{
    <div class="col-1"><input asp-for="@Model.CustomerSpecificJobCards[card].IsAssigned" /></div>
    <div class="col-9">@Model.CustomerSpecificJobCards[card].Products</div>
    <div class="col-2">@Model.CustomerSpecificJobCards[card].JobCardId</div>
}

[EDIT] Originally, I thought all the values were returned using the for loop, but it turns out only the .IsAssigned values are returned... Products and JobCardId are empty. I'm using Razor Pages for the first time. What am I doing wrong?

[Followup] After reading Rafalon's answer, I found this explanation of binding a complex collection with checkboxes in either a for or foreach loop. Plus, here is another excellent related link on data binding.

1
show the controller code and the model etc - Ric
Because asp-for uses the variable name to create the name and id of the input, and it needs to be indexable (e.g. <input name='CustomerSpecificJobCards_0__IsAssigned' id='CustomerSpecificJobCards[0].IsAssigned' /> - check the generated html). Same goes for mvc when you use Html.EditorFor(m => m.Property[index].Subprop), you need a for and not a foreach loop - Rafalon
@Model.CustomerSpecificJobCards[card].Products this is just text, if you want it returned, you need it to be an input (be it hidden - <input type="hidden" asp-for="Model.CustomerSpecificJobCards[card].Products" /> - or not) - same goes for JobCardId - Rafalon
Is see. Post this as an answer and I'll accept it. - DeveloperDan

1 Answers

0
votes

Short answer: check the generated HTML for both for and foreach and you'll see that with foreach, you can not expect the form to return the List correctly (with asp-for helper).

for is needed so you get indexable inputs, looking like:

<input name='CustomerSpecificJobCards[0].IsAssigned'
         id='CustomerSpecificJobCards_0__IsAssigned' />

You could still do it with foreach, but without asp-for it's quite tedious, and your model have to meet some requirements (having an index property for example).


Your other problem comes from the fact that @Model.CustomerSpecificJobCards[card].Products is text only.

Therefore you should either replace it with an input, just like IsAssigned, or else you can add a hidden input:

<input type="hidden" asp-for="Model.CustomerSpecificJobCards[card].Products" />

Same goes for JobCardId.