I have a form with a submit button that should pass through the item to the actionlistener. I thought it might be similar to the question in @Html.HiddenFor does not work on Lists in ASP.NET MVC but none of the answers seem to work. You can even see my for-loop taken from one of the answers in there.
[ EDIT: I have gotten rid of the mass of hidden loops and replaced with @Html.EditorFor so that you can see, even if not hidden, the flags list does not get to the actionlistener. This is a problem because when someone edits the flags, there is no way to update the db as I cannot get the ID of the flag updated. ]
The ModelState in the controller is never valid, regardless whether I keep the "[Bind(Include =" there or not. That's just there because of the tutorial for ASP.NET MVC Tutorial: Web application development with Azure Cosmos DB.
ItemController.cs:
[HttpPost]
[ActionName("ProductEdit")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> EditProductAsync( [Bind(Include = "Id, Name, Flags")] Item model)
{
Item product = await DocDBRepo<Item>.GetItem(model.Id);
model.Organisations = product.Organisations;
if (ModelState.IsValid) //Checks item validation via "required" set on properties
{
await DocDBRepo<Item>.UpdateItemAsync(model.Id, model);
return RedirectToAction("Index");
}
return View(model);
}
[HttpGet]
[ActionName("ProductEdit")]
public async Task<ActionResult> EditProductAsync(string id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Item item = await DocDBRepo<Item>.GetItem(id);
if (item == null)
{
return HttpNotFound();
}
return View(item);
}
ProductEdit.cs:
@model RRPortal.Models.Item
@{
ViewBag.Title = "ProductEdit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>ProductEdit</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(model => model.Id)
<div class="form-group">
@Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Flags, htmlAttributes: new { @class = "control-label col-md-2 " })
</div>
@*Flags list*@
@for (int i = 0; i < Model.Flags.Count; i++) //foreach (var flag in Model.Flags)
{
<div class="form-group">
//@Html.HiddenFor(modelItem => Model.Flags[i].Id)
@Html.Label(Model.Flags[i].Name, htmlAttributes: new { @class = "control-label col-md-3" })
@Html.LabelFor(modelItem => Model.Flags[i].Enabled, htmlAttributes: new { @class = "control-label col-md-1" })
<div class="col-md-8">
@Html.EditorFor(modelItem => Model.Flags[i].Enabled, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(modelItem => Model.Flags[i].Enabled, "", new { @class = "text-danger" })
</div>
</div>
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
Item.cs:
public class Item
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[Required]
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "flags")]
public List<Flag> Flags { get; set; }
[JsonProperty(PropertyName = "organisations")]
public List<Organisation> Organisations { get; set; }
}
public class Flag
{
[JsonProperty(PropertyName = "id")]
public int Id { get; set; }
[Required]
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[Required]
[JsonProperty(PropertyName = "enabled")]
public bool Enabled { get; set; }
}
public class Organisation
{
[JsonProperty(PropertyName = "id")]
public int Id { get; set; }
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "users")]
[Display(Name ="Users")]
public List<User> UserStore { get; set; }
}
public class User
{
[JsonProperty(PropertyName = "id")]
public int Id { get; set; }
[Required]
[JsonProperty(PropertyName = "fname")]
public string FName { get; set; }
[Required]
[JsonProperty(PropertyName = "lname")]
public string LName { get; set; }
[Required]
[Display(Name = "Admin?")]
[JsonProperty(PropertyName = "isadmin")]
public bool IsAdmin { get; set; }
}
The Item's Id and Name comes through and is not null when I debug the controller, but the Flags List is always empty. The ModelState shows the following exception: {"The parameter conversion from type 'System.String' to type 'RRPortal.Models.Flag' failed because no type converter can convert between these types."}
I have also been asked where the ModelState is showing the exception so below is a screenshot:
I will gladly update the question if anyone has any questions. I have been tweaking the view for 2 days now and still can't get the item to contain anything. The rendered HTML appears to contain the organisation and inner objects perfectly fine.
Any help is appreciated!