11

I have a class of Signature objects:

public class Signature
    {
        public int SignatureID { get; set; }
        public int FormID { get; set; }
        public string Title { get; set; }
        public string Email { get; set; }
        [Display(Name = "Signed Date:")]
        public DateTime? Date { get; set; }
    }

I have a Form.cs class that has a virtual list of signatures

public virtual List<Signature> Signatures { get; set; }

In my controller, I populate the list by:

form.Signatures = repository.Signatures.Where(s => s.FormID == form.FormID).ToList();

In my Form View, I display a list of the associated signatures:

@foreach (var signature in Model.Signatures)
    {
    <div class="text-center">
        <label asp-for="@signature.Title"></label>
        <input asp-for="@signature.Title" />
        <label asp-for="@signature.Email"></label>
        <input asp-for="@signature.Email" />
        <label asp-for="@signature.Date"></label>
        <input disabled asp-for="@signature.Date">
    </div>
    }

However, I don't know how to update the associated signatures upon my POST method of the form. For example, if I change the Email property of a signature and POST the form, the model does not bind this change into the Form object. In this case, form.Signatures is null.

How can I ensure changes to the <List>Signature items associated with the form are updated on POST?

coolhand
  • 1,876
  • 5
  • 25
  • 46

1 Answers1

25

Use the for loop to generate the elements, as it would add indexing to the property names which is used by model binder to bind to List on the post which does not work with the foreach:

@for (int i=0; i< Model.Signatures.Count; i++)
{
<div class="text-center">
    <label asp-for="@Model.Signatures[i].Title"></label>
    <input asp-for="@Model.Signatures[i].Title" />
    <label asp-for="@Model.Signatures[i].Email"></label>
    <input asp-for="@Model.Signatures[i].Email" />
    <label asp-for="@Model.Signatures[i].Date"></label>
    <input disabled asp-for="@Model.Signatures[i].Date">
</div>
}

Now the elements would be rendered with names like Signatures[0].Title, Signatures[1].Title and the model binder can bind it to the model on post.

Hope it helps.

Ehsan Sajjad
  • 61,834
  • 16
  • 105
  • 160
  • Thanks! This fixed the binding issue. Now I've got to track down a way to call a `save` function in my repo without using an iterative loop because that's causing an error – coolhand Mar 19 '18 at 14:33
  • glad to help and best of luck. – Ehsan Sajjad Mar 19 '18 at 14:36
  • One thing to note here is that if an item from the collection can be deleted (i.e: `@Model.Signatures[3]` is deleted entirely by a user) then the collection will not serialize properly. The indexes need to be in a consecutive order beginning at 0 – GregH Mar 19 '18 at 15:21
  • 1
    I would assume that the solution to that would be to use an isDeleted field in the Signature model and use whatever JavaScript/CSS techniques to gray out the input or convey the deleted status. Then when the form is posted, check that isDeleted field and handle it in the persistence tier. – tnk479 Feb 13 '21 at 15:00