Asp.Net MVC Custom Template and model not fill correctly on POST

In this year I work a lot in ASP.Net MVC and I found many bugs or trick.
Here a post where I descrive a bug that make me waste a lot of time.

If the model contain an array property

Tag[] Tags

you can display this list and using the EditorTemplate Tag.cshtml writing this code:

@Html.EditorFor(m => m.Tags)

And the EditorTemplate is Shared\EditorTemplates\Tag.cshtml

@model ODM.Models.Tag
<li>
  @Html.EditorFor(m =&gt; m.IsSelected)
  @Html.HiddenFor(m =&gt; m.IdTag)
  @Model.Title
</li>

This works correctly and che HTML generated is this:

<ul>
  <li>
    <input name="Category.TagType[0].Tags[0].IsSelected" class="check-box" id="Category_TagType_0__Tags_0__IsSelected" type="checkbox" checked="checked" value="true" data-val-required="The IsSelected field is required." data-val="true" />
    <input name="Category.TagType[0].Tags[0].IsSelected" type="hidden" value="false" />
    <input name="Category.TagType[0].Tags[0].IdTag" id="Category_TagType_0__Tags_0__IdTag" type="hidden" value="43" data-val-required="The IdTag field is required." data-val="true" data-val-number="The field IdTag must be a number." />
    Aggiornamento Professionale
  </li>
  <li>
    <input name="Category.TagType[0].Tags[1].IsSelected" class="check-box" id="Category_TagType_0__Tags_1__IsSelected" type="checkbox" checked="checked" value="true" data-val-required="The IsSelected field is required." data-val="true" />
    <input name="Category.TagType[0].Tags[1].IsSelected" type="hidden" value="false" />
    <input name="Category.TagType[0].Tags[1].IdTag" id="Category_TagType_0__Tags_1__IdTag" type="hidden" value="38" data-val-required="The IdTag field is required." data-val="true" data-val-number="The field IdTag must be a number." />
    Contratti di Lavoro
  </li>
  <li>
    <input name="Category.TagType[0].Tags[2].IsSelected" class="check-box" id="Category_TagType_0__Tags_2__IsSelected" type="checkbox" checked="checked" value="true" data-val-required="The IsSelected field is required." data-val="true" />
    <input name="Category.TagType[0].Tags[2].IsSelected" type="hidden" value="false" />
    <input name="Category.TagType[0].Tags[2].IdTag" id="Category_TagType_0__Tags_2__IdTag" type="hidden" value="44" data-val-required="The IdTag field is required." data-val="true" data-val-number="The field IdTag must be a number." />
    Disposizioni sui Trattamenti
  </li>
</ul>

If we need to use the template “TagEdit” the next line will throw an Error.

@Html.EditorFor(m => m.Tags, "TagEdit")

That because the template is designed for ODM.Models.Tag class and not for ODM.Models.Tag[].
This make sense but I don’t know why with the default template there is no problem…

So is necessary rewrite the code and apply the Editor template to every items
First I replace it with this:

foreach (var item in Model.Tags) 
{ 
  @Html.EditorFor(itm => item, "TagEdit") 
}

For example the template TagEdit is the same of Tag.cshtml

@model ODM.Models.Tag
<li>
  @Html.EditorFor(m => m.IsSelected)
  @Html.HiddenFor(m => m.IdTag)
  @Model.Title
</li>

Is selected is a bool and will be displayed as a checkbox

This works good only if we don’t need to obtain the values of some input present in the template.
So the foreach can be used ONLY to display and not to receive the items value in the list modified by a checkbox for example.
That because the HTML code generated by foreach istruction is that:

<ul>
  <li>
    <input name="Category.TagType[0].item.IsSelected" class="check-box" id="Category_TagType_0__item_IsSelected" type="checkbox" checked="checked" value="true" data-val-required="The IsSelected field is required." data-val="true" />
    <input name="Category.TagType[0].item.IsSelected" type="hidden" value="false" />
    <input name="Category.TagType[0].item.IdTag" id="Category_TagType_0__item_IdTag" type="hidden" value="43" data-val-required="The IdTag field is required." data-val="true" data-val-number="The field IdTag must be a number." />
    Aggiornamento Professionale
  </li>
  <li>
    <input name="Category.TagType[0].item.IsSelected" class="check-box" id="Category_TagType_0__item_IsSelected" type="checkbox" checked="checked" value="true" data-val-required="The IsSelected field is required." data-val="true" />
    <input name="Category.TagType[0].item.IsSelected" type="hidden" value="false" />
    <input name="Category.TagType[0].item.IdTag" id="Category_TagType_0__item_IdTag" type="hidden" value="38" data-val-required="The IdTag field is required." data-val="true" data-val-number="The field IdTag must be a number." />
    Contratti di Lavoro
  </li>
  <li>
    <input name="Category.TagType[0].item.IsSelected" class="check-box" id="Category_TagType_0__item_IsSelected" type="checkbox" checked="checked" value="true" data-val-required="The IsSelected field is required." data-val="true" />
    <input name="Category.TagType[0].item.IsSelected" type="hidden" value="false" />
    <input name="Category.TagType[0].item.IdTag" id="Category_TagType_0__item_IdTag" type="hidden" value="44" data-val-required="The IdTag field is required." data-val="true" data-val-number="The field IdTag must be a number." />
    Disposizioni sui Trattamenti
  </li>
</ul>

notice the HTML code generated by default.

name="Category.TagType[0].Tags[0].IsSelected"
name="Category.TagType[0].Tags[1].IsSelected"
name="Category.TagType[0].Tags[2].IsSelected"
...

and the HTML code generate by foreach

name="Category.TagType[0].item.IsSelected"
name="Category.TagType[0].item.IsSelected"
name="Category.TagType[0].item.IsSelected"
...

So with this code the POST method of the controller can’t recostruct the array Tag of the model.
I think this is a BUG.

To solve this replace the istruction “foreach” with “for”

@for (int i = 0; i < Model.Tags.Length; i++)
{
  @Html.EditorFor(m => m.Tags[i], "TagEdit")
}

and will be generate this HTML code:

 <ul>
  <li>
    <input name="Category.TagType[0].Tags[0].IsSelected" class="check-box" id="Category_TagType_0__Tags_0__IsSelected" type="checkbox" checked="checked" value="true" data-val-required="The IsSelected field is required." data-val="true" />
    <input name="Category.TagType[0].Tags[0].IsSelected" type="hidden" value="false" />
    <input name="Category.TagType[0].Tags[0].IdTag" id="Category_TagType_0__Tags_0__IdTag" type="hidden" value="43" data-val-required="The IdTag field is required." data-val="true" data-val-number="The field IdTag must be a number." />
    Aggiornamento Professionale
  </li>
  <li>
    <input name="Category.TagType[0].Tags[1].IsSelected" class="check-box" id="Category_TagType_0__Tags_1__IsSelected" type="checkbox" checked="checked" value="true" data-val-required="The IsSelected field is required." data-val="true" />
    <input name="Category.TagType[0].Tags[1].IsSelected" type="hidden" value="false" />
    <input name="Category.TagType[0].Tags[1].IdTag" id="Category_TagType_0__Tags_1__IdTag" type="hidden" value="38" data-val-required="The IdTag field is required." data-val="true" data-val-number="The field IdTag must be a number." />
    Contratti di Lavoro
  </li>
  <li>
    <input name="Category.TagType[0].Tags[2].IsSelected" class="check-box" id="Category_TagType_0__Tags_2__IsSelected" type="checkbox" checked="checked" value="true" data-val-required="The IsSelected field is required." data-val="true" />
    <input name="Category.TagType[0].Tags[2].IsSelected" type="hidden" value="false" />
    <input name="Category.TagType[0].Tags[2].IdTag" id="Category_TagType_0__Tags_2__IdTag" type="hidden" value="44" data-val-required="The IdTag field is required." data-val="true" data-val-number="The field IdTag must be a number." />
    Disposizioni sui Trattamenti
  </li>
</ul>

Good!!!

So remember to use the “foreach” statement only to display a list of model with custom template.
Use instead “for” statement to edit the list of model.

Annunci

Informazioni su Andrea Regoli

Project Manager .Net Developer WPF WP7 Asp.Net c# javascript ajax SQL sharepoint
Questa voce è stata pubblicata in .Net, Asp.Net, c#, MVC e contrassegnata con , , , , , . Contrassegna il permalink.

2 risposte a Asp.Net MVC Custom Template and model not fill correctly on POST

  1. Marco ha detto:

    Thanks for your personal marvelous posting! I
    actually enjoyed reading it, you will be a great author.I
    will make certain to bookmark your blog and may come back in the future.

    I want to encourage you to continue your great job, have a nice morning!

  2. forexground.pl ha detto:

    you’re actually a good webmaster. The site loading speed is amazing.
    It seems that you are doing any unique trick. In addition,
    The contents are masterpiece. you’ve done a fantastic job on this matter!

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...