I have a class which is called Ratings and has 5 different ratings (1=poor .. 5 = excellent). I also have a model (Review) which has 10 questions and each uses the ratings class. Now in the View I have a forEach for each of these properties in the Review class so the code is somewhat cut an paste. Rather than duplicating the code and just changing a property on them what I would like to do is create a method in the Ratings class which generates the razor syntax, if this is at all possible.
Sample on how it is now and what I would like to do is below.
Current View (only displaying 2 properties:
<tr>
<td class="control-label col-md-4">
#Html.LabelFor(model => model.ReviewModel.SpeakerReview, htmlAttributes: new { #class = "control-label " })
</td>
#foreach (var rating in ratingModel.RatingList)
{
<td class="col-md-1">
#Html.RadioButtonFor(model => model.ReviewModel.SpeakerReview, rating.RatingId)
</td>
}
</tr>
<tr>
<td class="control-label col-md-4">
#Html.LabelFor(model => model.ReviewModel.AvHandoutsApplicable, htmlAttributes: new { #class = "control-label " })
</td>
#foreach (var rating in ratingModel.RatingList)
{
<td class="col-md-1">
#Html.RadioButtonFor(model => model.ReviewModel.AvHandoutsApplicable, rating.RatingId)
</td>
}
</tr>
How I would like it to look:
View:
<tr>
<td class="control-label col-md-4">
#Html.LabelFor(model => model.ReviewModel.SpeakerReview, htmlAttributes: new { #class = "control-label " })
</td>
#ReviewModel.BuildRatingList(ratingModel, ReviewModel.SpeakerReview);
</tr>
<tr>
<td class="control-label col-md-4">
#Html.LabelFor(model => model.ReviewModel.AvHandoutsApplicable, htmlAttributes: new { #class = "control-label " })
</td>
#ReviewModel.BuildRatingList(ratingModel, ReviewModel.AvHandoutsApplicable);
</tr>
Class:
public static string BuildRatingList(Rating ratingModel, object reviewItem)
{
string RtnVal = "";
foreach (var rating in ratingModel.RatingList)
{
RtnVal = "<td class='col-md-1'>#Html.RadioButtonFor(model => " + reviewItem + ", rating.RatingId)</td>";
}
return RtnVal;
}
Thanks in advance!
While you can do almost exactly what you are asking by plugging in extra RazorEngine module from NUGET, I think you are better off using plain partial views or View Components, e.g. component:
namespace ViewComponentSample.ViewComponents
{
public class PriorityList : ViewComponent
{
private readonly ToDoContext db;
public PriorityList(ToDoContext context)
{
db = context;
}
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
var items = await GetItemsAsync(maxPriority, isDone);
return View(items);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db.ToDo
.Where(x => x.IsDone == isDone && x.Priority <= maxPriority)
.ToListAsync();
}
}
}
and view:
#using ViewComponentSample.Models
#using ViewComponentSample.ViewComponents
#model IEnumerable<TodoItem>
<h2>ToDo nameof</h2>
<div>
#await Component.InvokeAsync(nameof(PriorityList),
new { maxPriority = 4, isDone = true })
</div>
Related
I'm new to .net. I have this model that has been a real trouble for me for days.
class DetailedRecordModel
public class DetailedRecordModel
{
public string RecordID { get; set; }
public string EmployeeID { get; set; }
public string CustomerID { get; set; }
[DataType(DataType.Date)]
public string InitDate { get; set; }
[DataType(DataType.Date)]
public string DeliveryDate { get; set; }
public virtual ICollection<PurchaseDetail> detail{ get; set; }
}
class PurchaseDetail
public class PurchaseDetail
{
public string ProductID { get; set; }
public int Qty { get; set; }
public double price { get; set; }
public string RecordID { get; set; }
}
controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(DetailedRecordModel record)
{
if (ModelState.IsValid)
{
return View(record);
}
return RedirectToAction("ViewRecords");
}
html
<div class="form-group">
#Html.LabelFor(model => model.EmployeeID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.EmployeeID, (IEnumerable<SelectListItem>)ViewData["sellistemp"])
#Html.ValidationMessageFor(model => model.EmployeeID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.CustomerID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.CustomerID, (IEnumerable<SelectListItem>)ViewData["sellistcust"])
#Html.ValidationMessageFor(model => model.CustomerID, "", new { #class = "text-danger" })
</div>
</div>
<tr>
<td style="display:none" id="Index0" name="detail.Index" value="0"></td>
<td>1</td>
<td id="ProductID" name="detail[0].ProductID" value="sp00002">sp00002</td>
<td id="Qty" name="detail[0].Qty" value="12123">12123</td>
<td id="price" name="detail[0].price" value="2312">2312</td>
</tr>
<tr>
<td style="display:none" id="Index1" name="detail.Index" value="1"></td>
<td>2</td>
<td id="ProductID" name="detail[1].ProductID" value="sp00003">sp00003</td>
<td id="Qty" name="detail[1].Qty" value="2323">2323</td>
<td id="price" name="detail[1].price" value="3223">3223</td>
</tr>
for RecordID, EmployeeID, CustomerID, InitDate and DeliveryDate passing them to the controller is all fine, however I always get null for <PurchaseDetail> detail. How can I solve this problem?
you have to pass the model to the view by using View(myModel) or RedirectToAction("ViewRecords", record)
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(DetailedRecordModel record)
{
if (ModelState.IsValid)
{
return RedirectToAction("ViewRecords", record);
}
return View(record);
}
public IActionResult ViewRecords(DetailedRecordModel model)
{
return View(model);
}
then in the View you can access the model like here How to pass model in MVC view
add the definition of your model at the top of #model DetailedRecordModel;
after you added the model you can access it everywhere in your file with #Model (in html) or Model
#model DetailedRecordModel;
#{
ViewData["Title"] = "ViewRecords";
}
<h1>ViewRecords</h1>
<div class="form-group">
#Html.LabelFor(model => model.EmployeeID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.EmployeeID, (IEnumerable<SelectListItem>)ViewData["sellistemp"])
#Html.ValidationMessageFor(model => model.EmployeeID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.CustomerID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.CustomerID, (IEnumerable<SelectListItem>)ViewData["sellistcust"])
#Html.ValidationMessageFor(model => model.CustomerID, "", new { #class = "text-danger" })
</div>
</div>
#foreach (var entry in Model.detail)
{
<tr>
<td style="display:none" id="Index0" name="detail.Index" value="0"></td>
<td>1</td>
<td id="ProductID" name="#entry.ProductID" value="sp00002">sp00002</td>
<td id="Qty" name="#entry.Qty" value="12123">12123</td>
<td id="price" name="#entry.price" value="2312">2312</td>
</tr>
}
After 2 wretching days of desperation I know that in order to bind the values, I found the answer by declaring an object DetailedRecordModel inside model PurchaseDetail and I have to change the name of each <input> tag into detail[index].somevariable
I want to add students to the Attendance Table through the Class_Schedule controller. To do this I created an public ActionResult:
public ActionResult Register(int? id)
{
if (id == null)
{
return RedirectToAction("Index");
}
Class_Schedule class_Schedule = db.Class_Schedule.Find(id);
if (class_Schedule == null)
{
return RedirectToAction("Index");
}
//This is the collects the class_schedule ID to make the attendance specific for each class ViewBag.CSid = id;
ViewBag.studentID = new SelectList(db.Students, "StudentID", "Full_Name");
ViewBag.instructorID = new SelectList(db.Instructors, "InstructorID", "Name");
var attendances = db.Attendances;
return View(attendances.ToList());
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Register([Bind(Include = "AttendanceID,csID,InstructorID,StudentID")] Attendance attendance)
{
try
{
if (ModelState.IsValid)
{
db.Attendances.Add(attendance);
db.SaveChanges();
//ViewBag.msg = "Instructor Added";
return RedirectToAction("Register");
}
return View(attendance);
}
catch
{
return View(attendance);
}
}
This is my view:
#model IEnumerable<BBM.Models.Attendance>
#{
ViewBag.Title = "Register";
}
<h2>Class Schedule #ViewBag.CSid</h2>
#using (Html.BeginForm("Register","Class_Schedule", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-group">
#{
var studentid = Model.Select(model => model.StudentID.ToString());
}
#Html.Label("StudentID", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("StudentID", null, htmlAttributes: new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
<h4>Student register</h4>
<table class="table">
<tr>
<th>
Attendance ID
</th>
<th>
Student ID
</th>
<th>
Student Name
</th>
<th>
Expiry Date
</th>
</tr>
#if (Model != null)
{
foreach (var item in Model.Where(p => p.csID.Equals(ViewBag.csID)))
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.AttendanceID)
</td>
<td>
#Html.DisplayFor(modelItem => item.StudentID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Student.Full_Name)
</td>
<td>
#if (item.Student.Payments != null && item.Student.Payments.Any(p => p.Expires > DateTime.Now))
{
#Html.DisplayFor(modelItem => item.Student.Payments.OrderByDescending(p => p.paymentID).First(p => p.Expires > DateTime.Now).Expires)
}
else
{
#Html.DisplayName("Expired");
}
</td>
</tr>
}
}
</table>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
This view has a select list to select the students you want to add but but the student ID isn't going into the parameter and the postMethod isn't happening
The ones that are already in there are for test purposes and i did them through the sql server
You have only a specified drop-down id and html attribute. you forgot to pass data to the drop-down helper as you fill in the ViewBag. Update as below for student
#Html.DropDownList("StudentID",htmlAttributes:new { #class = "control-label col-md-2" },selectList:new SelectList(ViewBag.studentID))
Please check that you getting studentId on the post method.
I am new to ASP.NET MVC. I have a parent view and a partial view, both using different models. My concern is when I submit the page, the partial view data also should pass to the parent view HTTP Post method. I had created a property in the parent view model to get the data from the partial view model. But when I submit the page, I am getting null. any help would be appreciated
Parent view caseDetails.cshtml:
#model EMSD.Module.Case.CPN.Model.CPNDetailViewModel
#{
ViewBag.Title = "_CPNCaseDetail";
}
<table class="table table-striped">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<tr>
<td class="leftheaderform">
#Html.LabelFor(model => model.CPN_CAT)
<span style="color:red">*</span>
</td>
<td class="rightdetailform" colspan="3">
#Html.DropDownListFor(model => model.CPN_CAT, new SelectList(Model.InformedCat, "ID", "Name"), "--Select--", new { #class = "form-control form-control-sm col-3" })
#Html.ValidationMessageFor(model => model.CPN_CAT, "", new { #class = "text-danger" })
</td>
</tr>
<tr>
<td class="leftheaderform">
#Html.LabelFor(model => model.CPN_CAT_RMK)
</td>
<td class="rightdetailform" colspan="3">
#Html.TextAreaFor(model => model.CPN_CAT_RMK, new { htmlAttributes = new { #class = "form-control form-control-sm" }, rows = 2, style = "width: 100%; max-width: 100%;" })
#Html.ValidationMessageFor(model => model.CPN_CAT_RMK, "", new { #class = "text-danger" })
</td>
</tr>
*used HTML.partial for calling partial view*
#Html.Partial("~/Views/Shared/Address.cshtml", Model.Address)
</table>
Parent view model:
public class CPNDetailViewModel
{
[DisplayName("Informed Category")]
public string CPN_CAT { get; set; }
[DisplayName("Remarks ")]
public string CPN_CAT_RMK { get; set; }
// property for getting data from partial view
public UpdateGasSupplierViewModel Address { get; set; }
}
Partial view Address.chtml:
#model EMSD.Module.Misc.Model.UpdateGasSupplierViewModel
<table class="table table-striped">
<tr>
<td><font color="blue">Search Address</font></td>
<td colspan="4"> <input id="FreeEnglishAddressText" class="form-control" /></td>
<td><button type="button" onclick="callAPI()" class="btn btn-outline-primary form-control">Search</button></td>
</tr>
<tr>
<td>
Flat
</td>
<td>
#Html.DropDownListFor(model => model.GSC_ENG_FT, new SelectList(Model.FlatList, "ID", "Name"), "--Select--", new { #class = "form-control" })
</td>
<td>
#Html.EditorFor(model => model.GSC_ENG_FT_2, new { htmlAttributes = new { #class = "form-control" } })
</td>
</tr>
</table>
Partial view model:
namespace EMSD.Module.Misc.Model
{
public class UpdateGasSupplierViewModel
{
public string GSC_ID { get; set; }
public string GSC_COY_ENAME { get; set; }
}
}
Parent controller method:
[HttpPost]
public ActionResult _CPNCaseDetail(CPNDetailViewModel model)
{
string Post = Session["user_post"].ToString();
if (ModelState.IsValid)
{
cPNCaseService.Save(model);
}
return RedirectToAction("Case", "Case", new { Id = model.CASE_ID, Id2 = queueId, Id3 = "", Id4 = "Y" });
}
You need to use Templated helpers
Templated helpers are different than partials in that special contextual information from the parent is passed down to the child as long as we’re using the Html.EditorXyz() HtmlHelper methods.
Check This
This question already has answers here:
Post an HTML Table to ADO.NET DataTable
(2 answers)
Closed 5 years ago.
I am trying to call Action method "Createdirect" on form submission from Index.cshtml view.
I want to list and create in the same view. Code works for list..it displays data, but when trying to create, it does not pass form data to action method.. It passes null values as shown in screenshot attached..
Index.cshtml
#using CRUD_Entity_DataFirst.Models
#model Tuple<Customer_MVC,IEnumerable<Customer_MVC>>
#{
ViewBag.Title = "Index";
}
<h4>Customers</h4>
<link href="#Url.Content("~/Content/table.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Scripts/jquery-1.10.2.min.js")"></script>
<script src="#Url.Content("~/Scripts/select.js")"></script>
<script src="#Url.Content("~/Scripts/table.js")"></script>
#Html.DropDownList("searchby", new SelectList(Enum.GetValues(typeof(search))), "- - Search By - -")
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search ..">
<label id="bdy" style="color:red"></label>
<table class="table" id="myTable">
<tr>
<th>
#Html.DisplayNameFor(model => model.Item1.First_Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Item1.Last_Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Item1.Email)
</th>
<th>
#Html.DisplayNameFor(model => model.Item1.Mobile)
</th>
<th>
#Html.DisplayNameFor(model => model.Item1.Address_Temp)
</th>
<th>
#Html.DisplayNameFor(model => model.Item1.Address_Perm)
</th>
<th>
#Html.DisplayNameFor(model => model.Item1.State)
</th>
<th>
#Html.DisplayNameFor(model => model.Item1.City)
</th>
<th>
#Html.DisplayNameFor(model => model.Item1.Zipcode)
</th>
<th></th>
</tr>
#foreach (var item in Model.Item2)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.First_Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Last_Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Email)
</td>
<td>
#Html.DisplayFor(modelItem => item.Mobile)
</td>
<td>
#Html.DisplayFor(modelItem => item.Address_Temp)
</td>
<td>
#Html.DisplayFor(modelItem => item.Address_Perm)
</td>
<td>
#Html.DisplayFor(modelItem => item.State)
</td>
<td>
#Html.DisplayFor(modelItem => item.City)
</td>
<td>
#Html.DisplayFor(modelItem => item.Zipcode)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
#Html.ActionLink("View", "Details", new { id = item.Id }) |
#Html.ActionLink("Delete", "Delete", new { id = item.Id }, new { onclick = "return confirm('Are you sure wants to delete?');" })
</td>
</tr>
}
</table>
#using (Html.BeginForm("Createdirect","Customer",FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.EditorFor(model => model.Item1.First_Name, new { htmlAttributes = new { #class = "form-control", #style = "width:80px" } })
#Html.ValidationMessageFor(model => model.Item1.First_Name, "", new { #class = "text-danger" })
</div>
<div class="form-group">
#Html.EditorFor(model => model.Item1.Last_Name, new { htmlAttributes = new { #class = "form-control", #style = "width:80px" } })
#Html.ValidationMessageFor(model => model.Item1.Last_Name, "", new { #class = "text-danger" })
</div>
<div class="form-group">
#Html.EditorFor(model => model.Item1.Email, new { htmlAttributes = new { #class = "form-control", #style = "width:80px" } })
#Html.ValidationMessageFor(model => model.Item1.Email, "", new { #class = "text-danger" })
</div>
<div class="form-group">
#Html.EditorFor(model => model.Item1.Mobile, new { htmlAttributes = new { #class = "form-control", #style = "width:80px" } })
#Html.ValidationMessageFor(model => model.Item1.Mobile, "", new { #class = "text-danger" })
</div>
<div class="form-group">
#Html.EditorFor(model => model.Item1.Address_Temp, new { htmlAttributes = new { #class = "form-control", #style = "width:80px" } })
#Html.ValidationMessageFor(model => model.Item1.Address_Temp, "", new { #class = "text-danger" })
</div>
<div class="form-group">
#Html.EditorFor(model => model.Item1.Address_Perm, new { htmlAttributes = new { #class = "form-control", #style = "width:80px" } })
#Html.ValidationMessageFor(model => model.Item1.Address_Perm, "", new { #class = "text-danger" })
</div>
<div class="form-group">
#Html.DropDownListFor(model => model.Item1.State, new SelectList(Enum.GetValues(typeof(States))), "State", new { #class = "form-control", #style = "width:80px" })
#Html.ValidationMessageFor(model => model.Item1.State, "", new { #class = "text-danger" })
</div>
<div class="form-group">
#Html.DropDownListFor(model => model.Item1.City, new SelectList(Enum.GetValues(typeof(Cities))), "City", new { #class = "form-control", #style = "width:80px" })
#Html.ValidationMessageFor(model => model.Item1.City, "", new { #class = "text-danger" })
</div>
<div class="form-group">
#Html.EditorFor(model => model.Item1.Zipcode, new { htmlAttributes = new { #class = "form-control", #style = "width:80px" } })
#Html.ValidationMessageFor(model => model.Item1.Zipcode, "", new { #class = "text-danger" })
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
}
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
CustomerController.cs
// GET: Customer
public ActionResult Index()
{
if (Session["User"] == null)
{
return RedirectToAction("Login");
}
return View(Tuple.Create<Customer_MVC,IEnumerable<Customer_MVC>>(new Customer_MVC(),vd.Customer_MVC.ToList()));
}
//create:post
[HttpPost]
public ActionResult Createdirect(Customer_MVC custcreate)
{
if (ModelState.IsValid)
{
vd.Customer_MVC.Add(custcreate);
vd.SaveChanges();
return RedirectToAction("Index");
}
return View(custcreate);
}
Customer_MVC.cs
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace CRUD_Entity_DataFirst.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
[MetadataType(typeof(CustomersValid))]
public partial class Customer_MVC
{
public int Id { get; set; }
public string First_Name { get; set; }
public string Last_Name { get; set; }
public string Email { get; set; }
public string Mobile { get; set; }
public string Address_Temp { get; set; }
public string Address_Perm { get; set; }
public string City { get; set; }
public string State { get; set; }
public Nullable<int> Zipcode { get; set; }
}
}
here it showing null values
Model binding does not work when you use a foreach loop as the html controls are not rendered with meaningful IDs.
Change your loop to a for loop:
#for (int i = 0; i < Model.Item2.Length; i++)
{
<tr>
<td>
#Html.DisplayFor(model => model.Item2[i].First_Name)
</td>
<td>
...
You may also have an issue (but try it first) as the IEnumerable is not an instance at the point of binding. If this is the case then the only solution would be to change your Tuple based model to a class implementation:
public class MyModel
{
public Customer_MVC Item1 { get; set; }
public IEnumerable<Customer_MVC> Item2 { get; set; } = new List<Customer_MVC>();
}
I am writing a web page with MVC and Entity Framework.
I have an order with line items attached and want to return a complex object to the controller for processing.
I have now included all the code.
My view:
#model BCMManci.ViewModels.OrderCreateGroup
#{
ViewBag.Title = "Create";
}
<h2>New Order</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<h4>#Html.DisplayFor(model => model.Order.Customer.FullName)</h4>
<table>
<tr>
<td><b>Order Date:</b> #Html.DisplayFor(model => model.Order.OrderDate)</td>
<td><b>Status:</b> #Html.DisplayFor(model => model.Order.OrderStatus.OrderStatusName)</td>
</tr>
<tr>
<td colspan="2">
<b>Notes</b>
#Html.EditorFor(model => model.Order.Notes, new { htmlAttributes = new { #class = "form-control" } })
</td>
</tr>
</table>
#Html.ValidationMessageFor(model => model.Order.Notes, "", new { #class = "text-danger" })
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<table class="table table-striped table-hover">
<thead>
<tr>
<td>Name</td>
<td>Price</td>
<td>Discount</td>
<td>Total</td>
<td>Quantity</td>
</tr>
</thead>
<tbody>
#foreach (var product in Model.ProductWithPrices)
{
<tr>
<td>
#Html.DisplayFor(modelItem => product.ProductName)
</td>
<td>
#Html.DisplayFor(modelItem => product.SellingPrice)
</td>
<td>
#Html.DisplayFor(modelItem => product.DiscountPrice)
</td>
<td>
#Html.DisplayFor(modelItem => product.TotalPrice)
</td>
<td>
#Html.EditorFor(modelItem => product.Quantity, new { htmlAttributes = new { #class = "form-control" } })
</td>
</tr>
}
</tbody>
</table>
<input type="submit" value="Create" class="btn btn-default" />
}
<div class="btn btn-danger">
#Html.ActionLink("Cancel", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Order,ProductWithPrices,Order.Note,product.Quantity")] OrderCreateGroup order)
{
try
{
if (ModelState.IsValid)
{
db.Orders.Add(order.Order);
foreach (var orderItem in order.ProductWithPrices.Select(item => new OrderItem
{
OrderId = order.Order.OrderId,
ProductId = item.ProductId,
Quantity = item.Quantity,
ItemPrice = item.SellingPrice,
ItemDiscount = item.DiscountPrice,
ItemTotal = item.TotalPrice
}))
{
db.OrderItems.Add(orderItem);
}
db.SaveChanges();
return RedirectToAction("ConfirmOrder", new {id = order.Order.OrderId});
}
}
catch (DataException /* dex */)
{
//TODO: Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
}
ViewBag.Products = db.Products.Where(model => model.IsActive == true);
PopulateDropdownLists();
return View(order);
}
Data Source:
public class OrderCreateGroup
{
public OrderCreateGroup()
{
ProductWithPrices = new List<ProductWithPrice>();
}
public Order Order { get; set; }
public ICollection<ProductWithPrice> ProductWithPrices { get; set; }
}
public class ProductWithPrice : Product
{
public decimal SellingPrice { get; set; }
public decimal DiscountPrice { get; set; }
public int Quantity { get; set; }
public decimal TotalPrice { get; set; }
}
However, the values that are entered on the form are not being passed, through. So I can't access them in the controller. The 'productWithPrices' collection is null although there is Data in it on the web page.
I have tried making it asyc and also tried changing the ActionLink button like below but it didn't get to the controller.
#Html.ActionLink("Create", "Create", "Orders", new { orderCreateGoup = Model }, null)
This is the controller but it now doesn't make sense as the parameter passed in the datasource for the page.
public ActionResult Create(OrderCreateGroup orderCreateGoup)
Please, can you give me direction on the best way of doing this?
In your OrderCreateGroup class initialize the collection to an empty list.
public class OrderCreateGroup
{
public OrderCreateGroup()
{
ProductWithPrices = new List<ProductWithPrice>();
}
public Order Order { get; set; }
public ICollection<ProductWithPrice> ProductWithPrices { get; set; }
}
You'll need to add #Html.HiddenFor(m => m.SellingPrice) and similarly for other bound fields that are using DisplayFor if you want to post them back to the controller.
Note: For your benefit, try to have a look at the generated HTML code when your page is rendered in the browser and see what tags are generated inside the <form> tag with a name attribute.
make sure you bind the appropriate property from the complex object, like the following:
#model BCMManci.ViewModels.OrderCreateGroup
...
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
...
<div class="form-group">
#Html.LabelFor(model => model.LastName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.OrderCreateGroup.Order.Quantity, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.OrderCreateGroup.Order.Quantity, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Note:model.OrderCreateGroup.Order.Quantity would be one the your order's property.
hope this helps.