I'm pretty new to MVC and ASP.Net, my controller has 2 create methods for GET and POST. Through the Get
method I'm generating a list and sending it into the view. In the view I'm making changes to a specific value in each var in the list and trying to send it back to the controller and the POST
method.
When reaching the Post
method, the value of the list is null.
The list I'm sending is a list of products and I'm using a view model to create a class with common values to pass through to the view.
To pass through the IEnumerable
collection that was edited by the view I tried using BeginCollectionForm
, setting the items through ViewBag
, make changes to the model (@model IEnumerable<MarsBurgerV1.ViewModel.ItemVM>
), but still each time the checkout button is being pressed the list in the Post
method is NULL.
After a lot of tries and changes, currently my code looks as the following:
OrderController.cs
(relevant parts)
public class OrderController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
public ActionResult Create()
{
var meals = (from m in db.meals
select new ItemVM
{
Id = m.Id,
Name = m.Name,
Price = m.Price,
ItemType = "Meal",
ImageURL = m.ImageUrl,
Quantity = 0
}).ToList();
var drinks = (from d in db.drinks
select new ItemVM
{
Id = d.Id,
Name = d.Name,
Price = d.Price,
ItemType = "Drink",
Quantity = 0
}).ToList();
//More Like That....
List<ItemVM> items = new List<ItemVM>();
items.AddRange(meals);
items.AddRange(drinks);//More Like...
return View(items.ToList());
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(IEnumerable<ItemVM> items = null)
{
//Here items equals to null.
if (ModelState.IsValid)
{
//.....
}
return View();
}
Views/Order/Create.cshtml:
@model IEnumerable<***.ViewModel.ItemVM>
@{
ViewBag.Title = "Create";
var lst = Model.ToList();
ViewBag.List = Model.ToList();
}
<style>
tr td {
vertical-align: middle;
}
</style>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<h3> Order:</h3>
<table class="table table-condensed table-hover">
<tr calss="table-header">
<th>
@Html.DisplayName("Preview")
</th>
<th>
@Html.DisplayNameFor(m => m.Name)
</th>
<th>
@Html.DisplayNameFor(m => m.Price)
</th>
<th>
@Html.DisplayName("Quantity")
</th>
<th></th>
<th></th>
</tr>
@for (var i = 0; i < Model.Count(); i++)
{
<tr>
<td>
@if (Model.ElementAt(i).ImageURL != null)
{
<img src="@Url.Content(Model.ElementAt(i).ImageURL)" alt="IMAGES" height="100" width="100" />
}
</td>
<td>
@Html.DisplayFor(m => Model.ElementAt(i).Name)
</td>
<td>
@Html.DisplayFor(m => Model.ElementAt(i).Price)
</td>
<td>
<a type="button" class="btn btn-danger btn-xs" href="#">
<span class="glyphicon glyphicon-minus"></span>
</a>
@Html.EditorFor(l => lst[i].Quantity, new { htmlattribute = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => lst[i].Quantity, "", new { @class = "text-danger" })
<a type="button" class="btn btn-success btn-xs" id="plus" href="#">
<span class="glyphicon glyphicon-plus"></span>
</a>
</td>
</tr>
}
</table>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Checkout" class="btn btn-primary"/>
</div>
</div>
}
ViewModel/ItemVM.cs:
namespace ***.ViewModel
{
public class ItemVM
{
[Required]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
[DataType(DataType.Currency)]
public double Price { get; set; }
[Required]
public string ItemType { get; set; }
public string ImageURL { get; set; }
[Required]
public int Quantity { get; set; }
}
}
In the end I want to use the "Create" (HttpPost
method) to create a new order based on the values in the list received from the view.
What is the proper way of doing that and receiving the IEnumerable
into the POST
method?
Ok, I was finally able to make it work.
I've changed the @model
to List Type,
Add the (actionName, Controller, FormMethod)
to the HTML Helper Html.BeginForm
,
Used Model[i]
inside the loop to access variables and
marked all unchanged variables with
@Html.HiddenFor.
Create.cshtml:
@model List<MarsBurgerV1.ViewModel.ItemVM>
@{
ViewBag.Title = "Create";
}
@using (Html.BeginForm("Create","Order", FormMethod.Post))
{
@Html.AntiForgeryToken()
<h3> Order:</h3>
<table class="table table-condensed table-hover">
<tr calss="table-header">
<th>
@Html.DisplayName("Preview")
</th>
<th>
@Html.DisplayName("Name")
</th>
<th>
@Html.DisplayName("Price")
</th>
<th>
@Html.DisplayName("Quantity")
</th>
<th></th>
<th></th>
</tr>
@for (var i = 0; i < Model.Count(); i++)
{
<tr>
@Html.HiddenFor(m => Model[i].Id)
@Html.HiddenFor(m => Model[i].Type)
<td>
@Html.HiddenFor(m => Model[i].ImageURL)
@if (Model[i].ImageURL != null)
{
<img src="@Url.Content(Model[i].ImageURL)" alt="IMAGES" height="100" width="100" />
}
@Html.ValidationMessageFor(model => Model[i].ImageURL, "", new { @class = "label-control" })
</td>
<td>
@Html.HiddenFor(m => Model[i].Name)
@Html.DisplayFor(m => Model[i].Name)
@Html.ValidationMessageFor(model => Model[i].Name, "", new { @class = "label-control" })
</td>
<td>
@Html.HiddenFor(m => Model[i].Price)
@Html.DisplayFor(m => Model[i].Price, new { @class = "form-control" })
@Html.ValidationMessageFor(model => Model[i].Price, "", new { @class = "label-control" })
</td>
<td>
<a type="button" class="btn btn-danger btn-xs" href="#">
<span class="glyphicon glyphicon-minus"></span>
</a>
@Html.EditorFor(model => Model[i].Quantity, new { htmlattribute = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => Model[i].Quantity, "", new { @class = "text-danger" })
<a type="button" class="btn btn-success btn-xs" id="plus" href="#">
<span class="glyphicon glyphicon-plus"></span>
</a>
</td>
</tr>
}
</table>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" value="Checkout" class="btn btn-primary"/>
</div>
</div>
}
Thanks Everyone for the help.