I have an ASP.NET MVC 4 internet application with EF.
My model: Orders and OrderDetails:
My View:
Q: How can I display my orderdetails records in my order view? (with or without JS?; in a webgrid or a table?)
Create.cshtml
<div class="editor-label">
@Html.LabelFor(model => model.OrderDate)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.OrderDate)
@Html.ValidationMessageFor(model => model.OrderDate)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.OrderNo)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.OrderNo)
@Html.ValidationMessageFor(model => model.OrderNo)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Total)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Total)
@Html.ValidationMessageFor(model => model.Total)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Shipping)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Shipping)
@Html.ValidationMessageFor(model => model.Shipping)
</div>
@*OrderDetails Part - Works only on the Edit part*@
<table>
<tr>
<th>Product</th>
<th>Unit Price</th>
<th>Quantity</th>
<th>Discount</th>
</tr>
@foreach (OrderDetails item in Model.OrderDetails.OrderBy(d=>d.Products.ProductName))
{
<tr>
<td>@item.Products.ProductName</td>
<td>@item.UnitPrice</td>
<td>@item.Quantity</td>
<td>@item.Discount</td>
<td>
@Html.ActionLink("Edit", "Edit", "OrderDetails", new { id = item.OrderDetailId }, new { }) |
@Html.ActionLink("Details", "Details", "OrderDetails", new { id = item.OrderDetailId }, new { }) |
@Html.ActionLink("Delete", "Delete", "OrderDetails", new { id = item.OrderDetailId }, new { })
</td>
</tr>
}
</table>
<p>
<input type="submit" value="Create" />
</p>
You should be using viewmodels to achive this. You should not expose your business models directly to views. Instead use viewmodels to provide another level of abstraction.
So, do not change your models at all. Define a view model for your view. I will not be including all the fields in viewmodel.
/* Viewmodel for your Order/Create page */
public class OrderCreate
{
/* Attributes for your order */
public string OrderDate { get; set; }
public string OrderNo { get; set; }
public string Shipping { get; set; }
....
....
/* List that will contain all details */
public IList<ProductDetail> ProductDetails { get; set; }
}
/* Viewmodel for each of the products */
public class ProductDetail
{
public string Product { get; set; }
public string UnitPrice { get; set; }
public string Quantity { get; set; }
....
....
}
Now in your GET action, return this viewmodel to your view instead of your business model.
//
// GET: /Order/Create
public ActionResult Index()
{
/* New viewmodel for your view */
var viewModel = new OrderCreate();
viewModel.ProductDetails = new List<ProductDetail>();
/* Assuming the number of products is static */
for(int i = 0; i < NUMBER_OF_PRODUCTS; i++)
{
viewModel.ProductDetails.Add( new ProductDetail() );
}
return View(viewModel);
}
With this viewmodel you can now access the values filled in your view. When you post back your view to post action, create your business model there using the data from viewmodel.
//
// POST: /Order/Create
[HttpPost]
public ActionResult Index(OrderCreate viewModel)
{
if(ModelState.IsValid))
{
var model = new Order();
//TODO: Populate model through viewmodel, loop viewModel.ProductDetails
return RedirectToAction("Index");
}
// Model is not valid
return View(viewMode);
}
Some advices, if you become bored with mapping your viewmodels to actual models, try AutoMapper
Hope it helps.