I got stuck on a problem with returning from view to controller with related data, every time I submit my form with related data, the related data becomes null. (OrderRows)
I check the Chorme develop tool and saw that I do post the OrderRows as row.Id but can see them in Visual Studio as an variable
Classes
public class OrderModel
{
[Key]
public int Id { get; set; }
public int OrderID { get; set; }
public List<OrderRow> OrderRows { get; set; }
}
public class OrderRow
{
[Key]
public int Id { get; set; }
public int OrderID { get; set; }
public int OrderRowID { get; set; }
public OrderModel OrderModel { get; set; }
}
Edit Controller (GET)
public ActionResult Edit(int? id)
{
OrderModel orderModel = db.OrderModel.Where(b => b.Id == id).Include(b => b.OrderRows).FirstOrDefault();
return View(orderModel);
}
Delivered controler (Post, is activated when submitting the form)
public ActionResult Delivered(OrderModel orderModel, FormCollection formCollection)
{
//db.Entry(orderModel).State = EntityState.Modified;
//Set state to Delivered
//db.SaveChanges();
return RedirectToAction("Index");
}
Editview
using (Html.BeginForm())
{
#Html.LabelFor(model => model.OrderID): #Html.DisplayFor(model => model.OrderID)
#Html.HiddenFor(model => model.OrderRows)
<div class="row">
#Html.Label("Delivery information")
<br />
#Html.HiddenFor(model => model.Id, new { htmlAttributes = new { #class = "form-control" } })
#Html.DisplayFor(model => model.Id, "", new { #class = "text-danger" })
<br />
#Html.HiddenFor(model => model.OrderID, new { htmlAttributes = new { #class = "form-control" } })
#Html.DisplayFor(model => model.OrderID, "", new { #class = "text-danger" })
<br />
</div>
<table class="table table-striped table-bordered">
#foreach (var row in Model.OrderRows)
{
<tr>
<td>
<input type="checkbox" value="#row.OrderRowID">
</td>
<td>
#Html.HiddenFor(model => row.Id, new { htmlAttributes = new { #class = "form-control" } })
#Html.DisplayFor(model => row.Id, "", new { #class = "text-danger" })
</td>
<td>
#Html.HiddenFor(model => row.OrderID, new { htmlAttributes = new { #class = "form-control" } })
#Html.DisplayFor(model => row.OrderID, "", new { #class = "text-danger" })
</td>
<td>
#Html.HiddenFor(model => row.OrderRowID, new { htmlAttributes = new { #class = "form-control" } })
#Html.DisplayFor(model => row.OrderRowID, "", new { #class = "text-danger" })
</td>
<td>
#Html.HiddenFor(model => row.OrderModel, new { htmlAttributes = new { #class = "form-control" } })
#Html.DisplayFor(model => row.OrderModel, "", new { #class = "text-danger" })
</td>
</tr>
}
</table>
<div class="form-group">
<input type="submit" value="Mark as Delivered" formaction="/OrderModels/Delivered" class="btn btn-info" />
</div>
}
I think what you want is to use OrderRow instead OrderModel. If I understand what you need, you want to get (one) OrderModel and include (many) OrderRows. If that's what you want you should use OrderRow as your model in your view:
OrderRow orderRows = db.OrderRow.Where(b => b.OrderModel.Id == id).ToList();
return View(orderRows );
Then you want to change the model in your view:
#model IEnumberable<OrderRow>
This way, you can have all the OrderRows including its OrderModel
Your controller is defined as public ActionResult Edit(int? id), meaning it expects a value of id, of type int.
You won't get any other data through it, if you want the value from OrderRows you need to either change your form to submit it as id, or update your controller to accept a public ActionResult Edit(int OrderRows).
Either way, you are still also submitting a lot of junk that isn't being picked up by the controller, you need to only submit the values the controller is defined to accept (as above). What you really want to be doing is #html.BeginFrom(viewModelClass)'ing a viewmodel and submitting that to your controller with all the values.
Eg:
Public ActionResult Edit(ViewModel model)
{
var value = model.OrderRows
}
Related
I m implement a drop-down list with entity framework database first approach in asp.net MVC??
I implement a drop-down list in MVC and when I M debugging In watch Window My Inserted Record Is display but Not Inserted In Database that is an issue??
DatabaseField Name:
tbl_product
ProductID int
ProductName varchar(50)
ProductList varchar(50)
tbl_product.cs
// <auto-generated>
// </auto-generated>
public partial class tbl_product
{
public int ProductID { get; set; }
public string ProductName { get; set; }
public string ProductList { get; set; }
public IEnumerable<SelectListItem> ProductLists { get; set; }
}
HomeController.cs
ProductEntities prodb = new ProductEntities();
public ActionResult Index()
{
return View(prodb.tbl_product.ToList());
}
public ActionResult Prodlist()
{
var ProductLists = GetallProductList();
var model = new tbl_product();
model.ProductLists = GetSelectListItems(ProductLists);
return View(model);
}
[HttpPost]
public ActionResult Prodlist(tbl_product product)
{
var ProductLists = GetallProductList();
product.ProductLists = GetSelectListItems(ProductLists);
if (ModelState.IsValid)
{
prodb.tbl_product.Add(product);
return RedirectToAction("Index");
}
return View("Prodlist", product);
}
private IEnumerable<SelectListItem> GetSelectListItems(IEnumerable<string> elements)
{
var selectList = new List<SelectListItem>();
foreach (var element in elements)
{
selectList.Add(new SelectListItem
{
Value = element,
Text = element
});
}
return selectList;
}
private IEnumerable<string> GetallProductList()
{
return new List<string>
{
"FRIDGE",
"WASHING MACHINE",
"A.C",
};
}
}
view:
Prodlist.cshtml
<div class="form-group">
#Html.LabelFor(model => model.ProductName, htmlAttributes: new { #class = "control-label col-md-2" })
<div>
#Html.EditorFor(model => model.ProductName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ProductName, "", new { #class = "text-danger" })
</div>
</div>
//product list
<div class="form-group">
#Html.LabelFor(model => model.ProductList, htmlAttributes: new { #class = "control-label col-md-2" })
<div>
#Html.DropDownListFor(model => model.ProductList,Model.ProductLists,"Please Select Your Products:", new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ProductList, "", new { #class = "text-danger" })
</div>
</div>
Model1.Context.cs
// <auto-generated>
// </auto-generated>
public partial class ProductEntities : DbContext
{
public ProductEntities()
: base("name=ProductEntities")
{
}
public virtual DbSet<tbl_product> tbl_product { get; set; }
}
Index.cshtml
#model IEnumerable<DropdownInsertMvc.Models.tbl_product>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.ProductName)
</th>
<th>
#Html.DisplayNameFor(model => model.ProductList)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.ProductName)
</td>
<td>
#Html.DisplayFor(modelItem => item.ProductList)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.ProductID }) |
#Html.ActionLink("Details", "Details", new { id=item.ProductID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.ProductID })
</td>
</tr>
}
</table>
When I m Debugging In Watch Window:
ProductList "FRIDGE" string
ProductLists Count = 3 System.Collections.Generic.IEnumerable {System.Collections.Generic.List}
ProductName "Electronics" string
record is not inserted in the database??
You missed prodb.SaveChanges() after prodb.tbl_product.Add(product); in Prodlist method.
for more information about SaveChanges() you can follow this link
I created a Model, View, and Controller. In my view, I loop through the collection of , and I create a table with each listed, along with a Save button.
When I click the Save button, the only data returned to the controller are the ID and LandownerID -- all the other fields show as null.
I have spent most of today searching google, and trying multiple answers, none of which worked.
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "ID,ExemptionNumber,IssueDate,KillCount,TRAPPING,SHOOTING,DOGS,OTHER,NO_INDICATION,NOTES,SPECIES,E_LANDOWNER,EXEM_YEAR,MethodOfDisposal,NO_DATA")] ExempKillData exempKillData)
{
if (ModelState.IsValid)
{
db.Entry(exempKillData).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index","Owners");
}
return View(exempKillData);
}
View:
#model IEnumerable<Exemptions.Models.ExempKillData>
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Edit</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<table border="1" id="tbl">
<tbody>
..table headers snipped...
#foreach (var kill in Model)
{
<tr>
<td>
#Html.EditorFor(model => Model.First().ID, new { htmlAttributes = new { #class = "form-control", #readonly = "readonly" } })
</td>
<td>
#Html.EditorFor(model => Model.First().ExemptionNumber, new { htmlAttributes = new { #class = "form-control", #readonly = "readonly" } })
</td>
<td valign="top">
#Html.EditorFor(model => kill.IssueDate, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => kill.IssueDate, "", new { #class = "text-danger" })
</td>
<td valign="top">
#Html.EditorFor(model => kill.KillCount, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => kill.KillCount, "", new { #class = "text-danger" })
</td>
<td valign="top">
#Html.EditorFor(model => kill.TRAPPING, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => kill.TRAPPING, "", new { #class = "text-danger" })
</td>
<td valign="top">
#Html.EditorFor(model => kill.SHOOTING, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => kill.SHOOTING, "", new { #class = "text-danger" })
</td>
<td valign="top">
#Html.EditorFor(model => kill.DOGS, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => kill.DOGS, "", new { #class = "text-danger" })
</td>
<td valign="top">
#Html.EditorFor(model => kill.OTHER, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => kill.OTHER, "", new { #class = "text-danger" })
</td>
<td valign="top">
#Html.EditorFor(model => kill.NO_INDICATION, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => kill.NO_INDICATION, "", new { #class = "text-danger" })
</td>
<td valign="top">
#Html.EditorFor(model => kill.NOTES, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => kill.NOTES, "", new { #class = "text-danger" })
</td>
<td valign="top">
#Html.EditorFor(model => kill.SPECIES, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => kill.SPECIES, "", new { #class = "text-danger" })
</td>
<td valign="top">
#Html.EditorFor(model => kill.E_LANDOWNER, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => kill.E_LANDOWNER, "", new { #class = "text-danger" })
</td>
<td valign="top">
#Html.EditorFor(model => kill.EXEM_YEAR, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => kill.EXEM_YEAR, "", new { #class = "text-danger" })
</td>
<td valign="top">
#Html.EditorFor(model => kill.NO_DATA, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => kill.NO_DATA, "", new { #class = "text-danger" })
</td>
<td valign="top" align="center">
<input type="submit" value="Save" class="btn btn-default" />
</td>
</tr>
}
</tbody>
</table>
}
Model:
[Table("WHE.ExempKillData")]
public partial class ExempKillData
{
[Display(Name ="Exemption Number")]
public int? ExemptionNumber { get; set; }
[Display(Name = "Issue Date")]
[Column(TypeName = "datetime2")]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime? IssueDate { get; set; }
[Display(Name = "Kill Count")]
public int? KillCount { get; set; }
public int? TRAPPING { get; set; }
[Column(TypeName = "numeric")]
public int? SHOOTING { get; set; }
public int? DOGS { get; set; }
[Column(TypeName = "numeric")]
public int? OTHER { get; set; }
[Display(Name ="No Indication")]
public int? NO_INDICATION { get; set; }
[StringLength(200)]
public string NOTES { get; set; }
[StringLength(32)]
public string SPECIES { get; set; }
[Display(Name ="Landowner")]
public double? E_LANDOWNER { get; set; }
[Display(Name ="Exemption Year")]
[StringLength(4)]
public string EXEM_YEAR { get; set; }
[Display(Name ="No Data")]
[StringLength(40)]
public string NO_DATA { get; set; }
public string MethodOfDisposal { get; set; }
public int ID { get; set; }
}
}
I would expect that clicking Save would return the contents of that row back to the Controller Action, where the data could then be properly saved.
ModelState.IsValid is true for every record I try to edit, but as mentioned above, all fields except ID and E_Landowner are null.
Have you looked at the 'Network' tab in the inspector when you make a request? The parameters looks like below:
you can make a test on your environment right now. Inspect the element that is not binding correctly, and remove 'kill.' from its name:
When you press save, this single property should be bound correctly
The thing is, when you make 'EditorFor(model => kill.IssueDate), then the bolded text will be the parameter name when you make a request. So, if your model had a property of type ExempKillData, and named as 'kill', then the binding would work.
But no worries, I know what you want to do.
Just change the line
#Html.EditorFor(model => kill.IssueDate, new { htmlAttributes = new { #class = "form-control" } })
to
#Html.EditorFor(model => kill.IssueDate, null, "IssueDate", new { htmlAttributes = new { #class = "form-control" } });
the second parameter is a template which is not the one we're interested in that example, but the third one tells ASP.NET to set a different field name for that property.
I am rather dull when it comes to explaining, but I hope you got the idea :)
btw. You can remove all this 'Bind' text from method parameter. Only type and name of parameter is required
I am creating a form in a for loop in Razor.
#model SignAPI.ViewModels.ChannelManagerViewModel
#{
ViewBag.Title = "Index";
}
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#using (Html.BeginForm("Index", "ChannelManager", FormMethod.Post))
{
<div class="form-group">
#Html.LabelFor(m => m.CustomerNames, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(x => x.CustomerNameSelected, Model.CustomerNames, "Select", new { onchange = "this.form.submit();", #class = "form-control form-control-sm", #id = "CustomerDdl", #data_val = false })
#Html.ValidationMessageFor(m => m.CustomerNameSelected, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.Devices, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(x => x.DeviceSelected, Model.Devices, "Select", new { onchange = "this.form.submit();", #class = "form -control form-control-sm", #id = "DeviceDdl", #data_val = false })
#Html.ValidationMessageFor(m => m.DeviceSelected, "", new { #class = "text-danger" })
</div>
</div>
}
#using (Html.BeginForm("SaveData", "ChannelManager", FormMethod.Post))
{
<table class="table table-striped" style="font-size:small;">
<thead>
<tr>
<th>
Channel Name
</th>
<th>
UOM's'
</th>
<th>
Channel UOM
</th>
<th>
Calculated
</th>
<th></th>
</tr>
</thead>
<tbody>
#{ var channelNames = Model.ChannelNames.Select(x => x.ChannelName).OrderByDescending(x => Model.ChannelName).ToList();
for (int count = 0; count < channelNames.Count(); count++)
{
var channel = channelNames[count];
var ddlId = ("ddlId" + count).ToString();
var txtBoxId = ("txtBoxId" + count).ToString();
<tr>
#Html.HiddenFor(x => x.CustomerNameSelected)
#Html.HiddenFor(x => x.DeviceSelected)
<td>
#Html.Label(channel)
</td>
<td>
#Html.DropDownListFor(x => x.UomSelected, Model.Uom, "Select", new { #class = "form-control form-control-sm", #id = #ddlId, #data_val = false })
<script type="text/javascript">
$('##ddlId').change(function () {
$('##txtBoxId').val($(this).val());
});
</script>
</td>
<td>
#Html.EditorFor(x => x.ChannelDataToSave, Model.UomSelected, new { htmlAttributes = new { #id = #txtBoxId, #class = "form-control form-control-sm" } })
#Html.ValidationMessageFor(x => x.ChannelType, "", new { #class = "text-danger" })
</td>
<td>
#Html.CheckBoxFor(x => x.Calculated)
</td>
</tr>
}
}
</tbody>
</table>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-sm btn-primary" />
</div>
</div>
}
</div>
I want to pass all of the data created in the second form back to my Action using the ViewModel:
public class ChannelManagerViewModel
{
[Display(Name = "Select a customer")]
public IEnumerable<SelectListItem> CustomerNames { get; set; }
public string CustomerNameSelected { get; set; }
[Display(Name = "Select a device")]
public IEnumerable<SelectListItem> Devices { get; set; }
public string DeviceSelected { get; set; }
[Display(Name = "Channel Name")]
public string ChannelName { get; set; }
[Display(Name = "Channel Type")]
public string ChannelType { get; set; }
[Display(Name = "Calculated")]
public bool Calculated { get; set; }
public int ChannelCount { get; set; }
public List<ChannelManagerModel> ChannelNames { get; set; }
public List<ChannelManagerViewModel> ChannelDataToSave { get; set; }
private List<string> UomList {
get
{
var l = new List<string>();
l.Add("Electricity");
l.Add("Gas");
l.Add("Water");
l.Add("Heat");
l.Add("kWh");
l.Add("Wh");
l.Add("kVarh");
l.Add("Wh");
l.Add("Volts 1");
l.Add("Volts 2");
l.Add("Volts 3");
l.Add("Current 1");
l.Add("Current 2");
l.Add("Current 3");
l.Add("Hz");
l.Add("Litres");
l.Add("Cubic Metres");
l.Add("Cubic Feet");
return l;
}
}
public IEnumerable<SelectListItem> Uom {
get {
List<SelectListItem> sl = new List<SelectListItem>();
foreach (var item in UomList)
{
sl.Add(new SelectListItem() { Text = item, Value = item });
};
return sl;
}
set { }
}
public string UomSelected { get; set; }
}
I want to then save the data.
I have tried a number of things including using a partial view, but that doesn't work. I have also tried adding the loop index
#Html.EditorFor(x => x[count].ChannelDataToSave, Model.UomSelected, new { htmlAttributes = new { #id = #txtBoxId, #class = "form-control form-control-sm" } })
but this just tells me Cannot apply indexing with [] to an expression of type 'ChannelManagerViewModel'
I was hoping that the form would create a List<ChannelManagerViewModel> to pass back to the Action
[HttpPost]
public ActionResult SaveData(ChannelManagerViewModel vm)
{
//Do some stuff
return View(vm);
}
All it passes back is a null viewmodel.
Can you advise what is wrong with this?
The expected outcome is that when the form is created in the for loop, it creates a List to pass back to the Action in the Controller. Currently it doesn't...
TIA
I have been working on this and have been searching for hours and still can not figure out a solution.
I am trying to display the ItemNames of the checked checkboxes from my AsoociateMenuItems view to my Index view. Would appreciate any help I can get.
MenuItemViewModel:
public class MenuItemViewModel
{
public int MenuId { get; set; }
public double ItemPrice { get; set; }
public string ItemName { get; set; }
public bool Selected { get; set; }
public virtual ICollection<IngredientViewModel> Ingredients { get; set;}
}
OrderViewModel:
public class OrderViewModel
{
public int OrderId { get; set; }
public int TableNum { get; set; }
public string Notes { get; set; }
public double Discount { get; set; }
public virtual ICollection<MenuItemViewModel> MenuItem { get; set; }
}
Index:
#model IEnumerable<Final_POS.Models.Order>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Employee.EmpName)
</th>
<th>
#Html.DisplayNameFor(model => model.TableNum)
</th>
<th>
+
#Html.DisplayNameFor(model => model.Discount)
</th>
<th>
#Html.DisplayNameFor(model => model.MenuItems)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Employee.EmpName)
</td>
<td>
#Html.DisplayFor(modelItem => item.TableNum)
</td>
<td>
#Html.DisplayFor(modelItem => item.Discount)
</td>
<td>
#Html.EditorFor(modelItem => item.MenuItems)
</td>
<td>
#Html.ActionLink("Edit", "AsoociateMenuItems", new { id=item.OrderId }) |
#Html.ActionLink("Details", "Details", new { id=item.OrderId }) |
#Html.ActionLink("Delete", "Delete", new { id=item.OrderId })
</td>
</tr>
}
</table>
AsoociateMenuItems:
-this is a replacement for my edit view
#model Final_POS.Models.ViewModel.OrderViewModel
#{
ViewBag.Title = "AsoociateMenuItems";
}
<h2>AsoociateMenuItems</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>OrderViewModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.OrderId, new { htmlAttributes = new { #class = "form-control" } })
<div class="form-group">
#Html.LabelFor(model => model.TableNum, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.TableNum, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.TableNum, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.HiddenFor(model => model.Notes, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.HiddenFor(model => model.Notes, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Notes, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Discount, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Discount, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Discount, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.EmployeeEmpId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.EmployeeEmpId, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.EmployeeEmpId, "", new { #class = "text-danger" })
</div>
</div>
#Html.EditorFor(model => model.MenuItem)
<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>
This next code snippet is being used by my AsoociateMenuItems in this line #Html.EditorFor(model => model.MenuItem)
MenuItemViewModel: (View)
#model Final_POS.Models.ViewModel.MenuItemViewModel
<fieldset>
#Html.HiddenFor(model => model.MenuId)
#Html.CheckBoxFor(model => model.Selected)
#Html.DisplayFor(model => model.ItemName)
#Html.DisplayFor(model => model.ItemPrice)
</fieldset>
Controller:
public class OrdersController : Controller
{
private POSContext db = new POSContext();
// GET: Orders
public ActionResult Index()
{
var orders = db.Orders.Include(o => o.Employee);
return View(orders.ToList());
}
// GET: Orders/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Order order = db.Orders.Find(id);
if (order == null)
{
return HttpNotFound();
}
return View(order);
}
// GET: Orders/Create
public ActionResult Create()
{
ViewBag.EmployeeEmpId = new SelectList(db.Employees, "EmpId", "EmpName");
return View();
}
// POST: Orders/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "OrderId,TableNum,Discount,EmployeeEmpId")] Order order)
{
if (ModelState.IsValid)
{
db.Orders.Add(order);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.EmployeeEmpId = new SelectList(db.Employees, "EmpId", "EmpName", order.EmployeeEmpId);
return View(order);
}
// GET: Orders/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Order order = db.Orders.Find(id);
if (order == null)
{
return HttpNotFound();
}
ViewBag.EmployeeEmpId = new SelectList(db.Employees, "EmpId", "EmpName", order.EmployeeEmpId);
return View(order);
}
// POST: Orders/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "OrderId,TableNum,Discount,EmployeeEmpId")] Order order)
{
if (ModelState.IsValid)
{
db.Entry(order).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.EmployeeEmpId = new SelectList(db.Employees, "EmpId", "EmpName", order.EmployeeEmpId);
return View(order);
}
// GET: Orders/Delete/5
public ActionResult Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Order order = db.Orders.Find(id);
if (order == null)
{
return HttpNotFound();
}
return View(order);
}
// POST: Orders/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
Order order = db.Orders.Find(id);
db.Orders.Remove(order);
db.SaveChanges();
return RedirectToAction("Index");
}
public ActionResult AsoociateMenuItems(int? id)
{
Order _order = db.Orders.Find(id);
if (_order == null)
{
return HttpNotFound();
}
OrderViewModel _orderViewModel = new OrderViewModel()
{
OrderId = _order.OrderId,
Discount = _order.Discount,
TableNum = _order.TableNum,
EmployeeEmpId = _order.EmployeeEmpId
};
List<MenuItemViewModel> _menuItemViewModel = new List<MenuItemViewModel>();
foreach (MenuItem menuItem in db.MenuItems)
{
_menuItemViewModel.Add(new MenuItemViewModel()
{
MenuId = menuItem.MenuId,
ItemName = menuItem.ItemName,
ItemPrice = menuItem.ItemPrice,
Selected = _order.MenuItems.Contains(menuItem)
});
}
_orderViewModel.MenuItem = _menuItemViewModel;
return View(_orderViewModel);
}
[HttpPost]
public ActionResult AsoociateMenuItems(OrderViewModel _orderViewModel)
{
Order _order = db.Orders.Find(_orderViewModel.OrderId);
_order.MenuItems.Clear();
foreach (MenuItemViewModel _menuItemViewModel in _orderViewModel.MenuItem)
{
if (_menuItemViewModel.Selected)
{
MenuItem _menuItem = db.MenuItems.Find(_menuItemViewModel.MenuId);
_order.MenuItems.Add(_menuItem);
}
}
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
}
Let's start.
Your question is really hard for understanding. BUT I hope that I understood.
At first, you should use model in all views. It is really important. You MUST do it. The easiest way - just extend you OrderViewModel with EmpName
public class OrderViewModel
{
public int OrderId { get; set; }
public int TableNum { get; set; }
public string Notes { get; set; }
public double Discount { get; set; }
public string EmpName { get; set; }
public virtual ICollection<MenuItemViewModel> MenuItems { get; set; } //renamed to plural
}
Than change your Index View
#model IEnumerable<OrderViewModel>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.EmpName)
</th>
<th>
#Html.DisplayNameFor(model => model.TableNum)
</th>
<th>
#Html.DisplayNameFor(model => model.Discount)
</th>
<th>
#Html.DisplayNameFor(model => model.MenuItems)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.EmpName)
</td>
<td>
#Html.DisplayFor(modelItem => item.TableNum)
</td>
<td>
#Html.DisplayFor(modelItem => item.Discount)
</td>
<td>
#Html.EditorFor(modelItem => item.MenuItems)
</td>
<td>
#Html.ActionLink("Edit", "AsoociateMenuItems", new { id=item.OrderId }) |
#Html.ActionLink("Details", "Details", new { id=item.OrderId }) |
#Html.ActionLink("Delete", "Delete", new { id=item.OrderId })
</td>
</tr>
}
</table>
Than change the controller method Index (Just get menuitems from db also)
// GET: Orders
public ActionResult Index()
{
var orders = db.Orders.Include(o => o.Employee).Include(o => o.MenuItems);
var orderModels = new List<OrderViewModel>();
foreach(var _order in orders)
{
OrderViewModel _orderViewModel = new OrderViewModel()
{
OrderId = _order.OrderId,
Discount = _order.Discount,
TableNum = _order.TableNum,
EmpName = _order.Employee.EmpName
};
List<MenuItemViewModel> _menuItemViewModels = new List<MenuItemViewModel>();
foreach (MenuItem menuItem in order.MenuItems)
{
if(_order.MenuItems.Contains(menuItem)) //where selected is true
{
_menuItemViewModel.Add(new MenuItemViewModel()
{
MenuId = menuItem.MenuId,
ItemName = menuItem.ItemName,
ItemPrice = menuItem.ItemPrice,
});
}
}
_orderViewModel.MenuItems = _menuItemViewModels;
orderModels.Add(_orderViewModel);
}
return View(orderModels);
}
I hope you will understand what I meant. And sure, my code need code refactoring, but you can do it by yourself.
I have read several answers on this issue but despite this, it would appear I have developed code blindness.
I have the following view model:
public class IndividualProductVm
{
public virtual Products Products { get; set; }
public ProductSummary ProductSummary { get; set; }
public virtual IEnumerable<ProductSimpleResponse> ProductSimpleResponse { get; set; }
}
This is then passed into a view and then a partial view:
#model Websites.ViewModels.IndividualProductVm #{ ViewBag.Title = "Edit"; }
<h2>Edit</h2>
#using (Html.BeginForm(null, null, FormMethod.Post, new { name = "form", id = "mainForm" })) { #Html.AntiForgeryToken() #Html.ValidationSummary(true, "", new { #class = "text-danger" }) #Html.HiddenFor(model => model.Products.Id) #Html.HiddenFor(model
=> model.ProductSummary.SupplierId) Html.RenderPartial("_IndividualProduct", Model);
<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>
#Html.ActionLink("Back to List", "Index", new { id = Model.ProductSummary.SupplierId }, new { #class = "btn btn-default" })
</div>
#section Scripts { #Scripts.Render("~/bundles/jqueryval") }
#model Websites.ViewModels.IndividualProductVm
<div>
#Html.LabelFor(model => model.Products.ProductCode, htmlAttributes: new { #class = "control-label col-md-2" })
<div>
#Html.DisplayFor(model => model.Products.ProductCode, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div style="clear:both;"></div>
<div>
#Html.LabelFor(model => model.Products.ProductDescription, htmlAttributes: new { #class = "control-label col-md-2" })
<div>
#Html.DisplayFor(model => model.Products.ProductDescription, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<table class="table">
<tr>
<th>
Present
</th>
</tr>
#foreach (var item in Model.ProductSimpleResponse)
{
<tr>
#Html.HiddenFor(modelItem => item.Id)
#Html.HiddenFor(modelItem => item.SupplierId)
#Html.HiddenFor(modelItem => item.ProductCode)
<td>
#Html.EditorFor(modelItem => item.Present)
</td>
</tr>
}
</table>
However, when I enter the edit post, my viewmodel is null for the IEnumerable<ProductSimpleResponse> but fine for the other two classes.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(IndividualProductVm model)
{
if (ModelState.IsValid)
{
return RedirectToAction("Index", new { id = model.ProductSummary.SupplierId });
}
return View(model.Products);
}
If someone can explain what I'm doing wrong, I'd be most grateful.
Your property name is ProductSimpleResponse, alhtough the type is ProductSvhcSimpleResponse, so to iterate through it you should have.
#foreach (var item in Model.ProductSimpleResponse)
NOT
#foreach (var item in Model.ProductSvhcSimpleResponse)
use List because
IEnumerable is suitable just for iterate through collection and you can not modify (Add or Remove) data IEnumerable bring ALL data from server to client then filter them, assume that you have a lot of records so IEnumerable puts overhead on your memory.
public class IndividualProductVm
{
public virtual Products Products { get; set; }
public ProductSummary ProductSummary { get; set; }
public virtual List<ProductSvhcSimpleResponse> ProductSimpleResponse { get; set; }
}
More help click here