I read most of Google :-), but I can’t proceed. The collection on my object is and stays null on post, whatever I do.
My Model:
public class ArticleViewModel
{
public Guid EventId { get; set; }
public IList<ArticleItemViewModel> ArtikelListe { get; set; }
public decimal GesamtpreisNetto { get; set; }
public decimal MwSt { get; set; }
}
and
public class ArticleItemViewModel
{
public Guid EventId { get; set; }
public Guid Id { get; set; }
public string Artikelname { get; set; }
public string Artikelname_EN { get; set; }
public string Information { get; set; }
public string Information_EN { get; set; }
public decimal Preis { get; set; }
public bool MitAnzahl { get; set; }
public bool IstKategorie { get; set; }
public int Anzahl { get; set; }
public bool Checkbox { get; set; }
public int Reihenfolge { get; set; }
}
My View:
@using (Html.BeginForm("Next", "Article", FormMethod.Post))
{
@Html.HiddenFor(x => x.EventId)
<input type="hidden" name="ArtikelListe" />
for (var i = 0; i < Model.ArtikelListe.Count; i++)
// foreach (EventManager.ViewModels.ArticleItemViewModel artikelItem in Model.ArtikelListe)
{
<div>
<div>
@if (Model.ArtikelListe[i].IstKategorie)
{
@Html.LabelFor(x => x.ArtikelListe[i].Artikelname)<br />
@Html.LabelFor(x => x.ArtikelListe[i].Information)
}
else
{
if (Model.ArtikelListe[i].MitAnzahl)
{
@Html.TextBoxFor(x => x.ArtikelListe[i].Anzahl, new { @class = "field text fn" })
}
else
{
@Html.LabelFor(x => x.ArtikelListe[i].Anzahl)
}
@Html.LabelFor(x => x.ArtikelListe[i].Artikelname)<br />
@Html.LabelFor(x => x.ArtikelListe[i].Information)
}
</div>
</div>
}
On post, I get my Viewmodel back and it has a Collection of ArtikelListe with 15 items (thats correct), but these are all null!
In my HTTP Header I get the following post data:
EventId:824e7f3c-7190-4ebb-aa60-51b57c977b1e ArtikelListe: ArtikelListe[1].Anzahl:0 ArtikelListe[2].Anzahl:1 ArtikelListe[3].Anzahl:0 submitButton:Nächste
I wonder why just partial data is sent withon the http post and why all my list items are null. I tried to render by for and foreach. same result.
Any ideas? I’m helpless.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
Collection indexers must start at zero and be consecutive (unless you include an Index property).Because of your if statements, you are not necessarily generating a control for the property Anzahl. Looking at your header information, you do not have a value for ArtikelListe[0].Anzahl which means that the first item must have either IstKategorie=true or MitAnzahl=false. You can correct this by adding a hidden input so a value posts back
@if (Model.ArtikelListe[i].IstKategorie)
{
@Html.LabelFor(x => x.ArtikelListe[i].Artikelname)<br />
@Html.LabelFor(x => x.ArtikelListe[i].Information)
@Html.HiddenFor(x => x.ArtikelListe[i].Anzahl) // add this
}
else
{
if (Model.ArtikelListe[i].MitAnzahl)
{
@Html.TextBoxFor(x => x.ArtikelListe[i].Anzahl, new { @class = "field text fn" })
}
else
{
@Html.LabelFor(x => x.ArtikelListe[i].Anzahl)
@Html.HiddenFor(x => x.ArtikelListe[i].Anzahl) // add this
}
@Html.LabelFor(x => x.ArtikelListe[i].Artikelname)<br />
@Html.LabelFor(x => x.ArtikelListe[i].Information)
}
Alternatively you can add an Index property which the DefaultModelBinder uses to match up collection items that are non-consecutive
@if (Model.ArtikelListe[i].IstKategorie)
{
@Html.LabelFor(x => x.ArtikelListe[i].Artikelname)<br />
@Html.LabelFor(x => x.ArtikelListe[i].Information)
}
else
{
if (Model.ArtikelListe[i].MitAnzahl)
{
@Html.TextBoxFor(x => x.ArtikelListe[i].Anzahl, new { @class = "field text fn" })
<input type="hidden" name="x.ArtikelListe.Index" value="@i" /> // add this manually
}
else
{
@Html.LabelFor(x => x.ArtikelListe[i].Anzahl)
}
@Html.LabelFor(x => x.ArtikelListe[i].Artikelname)<br />
@Html.LabelFor(x => x.ArtikelListe[i].Information)
}
With the first option, it will post back all items. In the second case it will post back only items that meet the if conditions.
Note as Sergey noted, you need to also remove <input type="hidden" name="ArtikelListe" />
Method 2
The issue in this line:
<input type="hidden" name="ArtikelListe" />
When POST request is sent back:
ArtikelListe: ArtikelListe[1].Anzahl:0 ArtikelListe[2].Anzahl:1 ArtikelListe[3].Anzahl:0
Then ArtikelListe overrides value for the list and that’s why it’s always null.
So you just need to rename your hidden field to some another name to not conflict with existing names.
Here is working example based on your MVC code in DotNetFiddle – https://dotnetfiddle.net/BCXduq
You can click RUN, then enter some values in two input fields in the right bottom box, and click Save button. And then it will display model that server received in POST as JSON text.
Method 3
Thank you guys.
The problem was, that I did the testing with the script from the Fiddle. In this code
Model.ArtikelListe[i].MitAnzahl
was always true.
In case it is not true, the value “Anzahl” was not bound to a control containing a value (but just a label).
@Html.LabelFor(x => x.ArtikelListe[i].Anzahl)
As soon as I inserted a hidden field within that scope and bound the “Anzahl” value to it, the post returned with all the data I expected.
Thanks anyway. I learned a lot!
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0