3

This question seems to be asked a lot. I went through everything I could find on StackOverflow regarding this and as far as I can tell, I'm doing everything I should be doing as far as making sure that the view iterates through the list elements properly and creates proper html for them. Yet, the model binding does not work.

I have these two view models:

public class ProjectViewModel
{
    public int ProjectId { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }

    public int? StatusId { get; set; }

    public IList<CoordinateViewModel> Coordinates;
}

public class CoordinateViewModel
{
    public int CoordinateId { get; set; }
    public double X { get; set; }
    public double Y { get; set; }
}

They are used like this in a view ( simplified for ease of reading ):

@model ProjectViewModel

<div class="container">
    <form asp-action="Edit" method="post">

        <div asp-validation-summary="All" class="text-danger"></div>

        <div class="row">
            Coordinates
            <table>
                <thead>
                    <tr>
                        <th></th>
                        <th>X</th>
                        <th>Y</th>
                    </tr>
                </thead>
                <tbody>
                    @for (int i = 0; i < Model.Coordinates.Count; i++)
                    {
                    <tr>
                        <td>@Html.HiddenFor(x => Model.Coordinates[i].CoordinateId)</td>
                        <td>@Html.TextBoxFor(x => Model.Coordinates[i].X)</td>
                        <td>@Html.TextBoxFor(x => Model.Coordinates[i].Y)</td>
                    </tr>
                    }
                </tbody>
            </table>

        </div>

        <div class="row">
            <div class="col-md-8 form-group">
                <label asp-for="Description" class="control-label"></label>
                <textarea asp-for="Description" class="form-control"></textarea>
                <span asp-validation-for="Description" class="text-danger"></span>
            </div>
        </div>
        <div class="row">
            <div class="form-group">
                <div class="col-md-offset-2 col-md-5">
                    <input type="submit" class="btn btn-primary" value="Submit" />
                </div>
            </div>
        </div>
    </form>
</div>

And the controller action that gets involved is this one ( again edited down for ease of reading ):

    [HttpPost]
    [ValidateAntiForgeryToken]
    public IActionResult Edit(ProjectViewModel viewModel)
    {

        return View(viewModel);
    }

When the form loads, the Coordinate information is populated.

When the form is submitted, the view model coming in on the action method of the controller contains a null value for the Coordinates property, and I can't figure out why.

user2316154
  • 302
  • 2
  • 13

1 Answers1

0

You are doing everything right as far as the view is concerned:

  1. Iterate over the elements in a for loop
  2. Use HTML helpers to create elements using the for loop's indexer

However, you did something wrong in your view model:

public IList<CoordinateViewModel> Coordinates;

For model binding to work, your view model needs to expose properties for the model binder to work with. In this case, Coordinates is a field, not a property. Change this to:

public IList<CoordinateViewModel> Coordinates {get; set; } 

Now your model binding will work.

user2316154
  • 302
  • 2
  • 13
  • 3
    Wow, you answered your own question quickly. But why are you referring to yourself as "you"?? – Andez Feb 25 '18 at 18:23
  • @Andez - I suppose because I have this habit of talking to myself as I code ... I am my own rubber ducky. – user2316154 Feb 25 '18 at 18:29