0

In my code I cannot read a nested object value on form post.

Wrog way to edit List property in one Object:

 @{
        var contatore = 0;

        foreach (var item in Model.Movimenti)
        {
            var movimento = item;

            <tr>
                <td align="left">
                    @*Imposto gli Hidden per tutte le proprietà che devo recuperare al post*@
                    @Html.HiddenFor(x => movimento.Prodotto.Descrizione, "Movimenti[" + contatore + "].Prodotto.Descrizione")

                    @Html.DisplayFor(x => movimento.Prodotto.Descrizione, "Movimenti[" + contatore + "].Prodotto.Descrizione")
                </td>
                <td>@Html.EditorFor(x => movimento.Aum, "CurrencyDisabled", "Movimenti[" + contatore + "].AUM")</td>
            </tr>
            contatore++;
        }
    }

This is the correct way to edit List property in one Object:

The code:

@using AI.Business.Models
@model Operazione
@{    ViewBag.Title = "Simulatore"; }
@using (Html.BeginForm("CreaOperazione", "Operativita", FormMethod.Post))
{     
// Imposto gli Hidden per tutte le proprietà che devo recuperare al post
@Html.HiddenFor(x => x.RapportoModel.TipoRapportoId)

<table width="100%" class="display" id="Simulatore" cellspacing="0">

    <thead>
    <tr>
        <th class="dt-head-left">Linea</th>
        <th>AUM</th>
    </tr>
    </thead>
    <tbody>
        @Html.EditorFor(x => x.Movimenti)
    </tbody>

</table>
<button id="btnSalva" name="btnSalva" type="submit" style="float: right;">Salva Operazione</button>

}

With the editor assuggested:

@model AI.Business.Models.Movimento
<tr>
<td align="left">
@Html.HiddenFor(x => x.Prodotto.Descrizione)
@Html.DisplayFor(x => x.Prodotto.Descrizione)</td>
<td>@Html.EditorFor(x => x.Aum, "CurrencyDisabled")</td>

And this is my object:

public class Movimento
{
    public int Id { get; set; }
    public ProdottoModel Prodotto { get; set; }
    public decimal Aum { get; set; }
}

And the Object Prodotto:

public class ProdottoModel
{    
    [Key]
    public int ID { get; set; }
    public string Descrizione { get; set; }
}

In my Actionresult the property Descrizione is null:

[HttpPost]
    public ActionResult CreaOperazione(Operazione operazione)
    {
        if (ModelState.IsValid)
        {
            // Do something
        }
        else
            ImpostaErrore(ModelState);

        return View("PaginaSimulatore", operazione);
    }

Open the images:
At my first access to the page the property Prodotto.Descrizione is populated

When i raise the form post event this property was sent with a null value

  • At the form post I can read correctly the property AUM, but not the property Prodotto.Descrizione that is null. – Sara Mafrica Jun 23 '16 at 13:02
  • 1
    You cannot use a `foreach` loop to generate form controls for a collection - refer [this answer](http://stackoverflow.com/questions/30094047/html-table-to-ado-net-datatable/30094943#30094943) –  Jun 23 '16 at 13:04
  • And if your getting a `NullReference` exception, its because `Prodotto` is `null` –  Jun 23 '16 at 13:11
  • Prodotto have a value in view, and when i raise the form post in my actionresult Prodotto is null – Sara Mafrica Jun 23 '16 at 13:20
  • Because you cannot use a `foreach` loop - read the link I gave you. –  Jun 23 '16 at 13:33
  • I've red it, but this code works correctly for all properties like AUM: @Html.EditorFor(x => movimento.Aum, "CurrencyDisabled", "Movimenti[" + contatore + "].AUM") - For this property after the post I can see the correct value. Only for the sub-object in my sub-propery I cannot see the value. Anyway I'll test the code in your link. Thanks – Sara Mafrica Jun 23 '16 at 13:40
  • Thank a lot. I've added the Hidden field to the Editor and it's work. – Sara Mafrica Jun 23 '16 at 14:28
  • It does not work and never will despite what you think. If you generate a collection you must use a `for` loop or custom `EditorTemplate` and you must post back the model you originally used in the view. –  Jun 23 '16 at 22:24

1 Answers1

1

I'm not sure how you're getting any of this to work, but it's a total fluke. HiddenFor, for example, has no parameter that let's you specify the name value for the field. Instead, where you're trying to do that, the parameter is actually for htmlAttributes, which expects either an anonymous object or IDictionary. The only reason you aren't getting errors is because string is technically an object, but it will never do anything in this context.

The same goes for the rest of your helper calls. With EditorFor, in particular, the second param where you're passing "CurrencyDisabled", is for specifying the editor template that should be used, and the third param is for additionalViewData, which just appends items to ViewData within the context of the editor template.

Long and short, none of this works how you think it does. Plainly and simply, if you need to work with a collection, you need to use for rather than foreach. The expression that you pass to the *For family of helpers is not just about identifying a property however you can get to it; it must be a bindable expression, i.e. something Razor can use to create a name for the form field that will line up to something on your model on post. In order for that to happen, the names must be something like Movimenti[N].Prodotto.Descrizione, and the only way to get that is to call the helper like:

 @Html.HiddenFor(m => m.Movimenti[i].Prodotto.Descrizione)

Where i would be the iterator from your for loop.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444