After reading this tutorial http://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/reading-related-data-with-the-entity-framework-in-an-asp-net-mvc-application I have created some models, controllers and views.
The recipes are showing just fine in the view, but I can't get the RecipeLines to show.
RecipeModel
public class RecipeModel
{
[Key]
public int RecipeId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string ImageUrl { get; set; }
public virtual ICollection<RecipeLine> RecipeLines { get; set; }
}
RecipeLine
public class RecipeLine
{
[Key]
public int RecipeLineId { get; set; }
public int RecipeId { get; set; }
public double Quantity { get; set; }
public UnitOfMeasureModel UnitOfMeasure { get; set; }
public IngredientModel Ingredient { get; set; }
}
RecipeViewModel
public class RecipeViewModel
{
public IEnumerable<RecipeModel> RecipeModels { get; set; }
public IEnumerable<RecipeLine> RecipeLines { get; set; }
}
Recipecontroller
public class RecipeController : Controller
{
private RecipeApplicationDb db = new RecipeApplicationDb();
[HttpGet]
public ActionResult Index(int? id)
{
var viewModel = new RecipeViewModel();
viewModel.RecipeModels = db.Recipes
//.Include(i => i.Name)
.Include(i => i.RecipeLines);
if (id != null)
{
ViewBag.RecipeId = id.Value;
viewModel.RecipeLines = viewModel.RecipeModels.Where(i => i.RecipeId == id.Value).Single().RecipeLines;
}
return View(viewModel);
}
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
RecipeModel recipeModel = db.Recipes.Find(id);
if (recipeModel == null)
{
return HttpNotFound();
}
return View(recipeModel);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
And the view
#model RecipeApplication.Models.RecipeViewModel
#{
ViewBag.Title = "Recepten";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
Naam
</th>
<th>
Omschrijving
</th>
<th>
Afbeelding
</th>
</tr>
#foreach (var item in Model.RecipeModels) {
string selectedRow = "";
if(item.RecipeId == ViewBag.RecipeId)
{
selectedRow = "success";
}
<tr class="#selectedRow" valign="top">
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
<td>
#if (item.ImageUrl != null)
{
#Html.DisplayFor(modelItem => item.ImageUrl)
}
</td>
<td>
#Html.ActionLink("Select", "Index", new { id = item.RecipeId}) |
#Html.ActionLink("Edit", "Edit", new { id=item.RecipeId }) |
#Html.ActionLink("Details", "Details", new { id=item.RecipeId }) |
#Html.ActionLink("Delete", "Delete", new { id=item.RecipeId })
</td>
</tr>
}
</table>
#if (Model.RecipeLines != null)
{
foreach (var item in Model.RecipeLines)
{
string selectedRow = "";
if (item.RecipeId == ViewBag.id)
{
<p>#item.Quantity #item.UnitOfMeasure #item.Ingredient</p>
}
}
}
When selecting the recipe, the line does get a proper color, and I see an id-value in the URL-string.
If someone could help with this one, that would be awesome.
You're comparing item.RecipeId to ViewBag.id, which doesn't exist. The ViewBag member you set in the controller action was ViewBag.RecipeId.
However, you don't need this conditional at all. All of the recipe lines are already for that recipe id, because you specifically set only those recipe items in Model.RecipeLines.
//change your controller action
[HttpGet]
public ActionResult Index(int? id)
{
if(id == null) return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
var model = new RecipeViewModel();
var data = db.RecipeModel.Include(i => i.RecipeLines)
.Where(x=>x.RecipeId == id)
.ToList();
model.RecipeModels = data;
return View(model);
}
//change your viewModel
public class RecipeViewModel
{
public IEnumerable<RecipeModel> RecipeModels { get; set; }
}
//this is in the view
#if (Model.RecipeLines != null)
{
foreach (var item in Model.RecipeModels.RecipeLines)
{
<p>
#item.Quantity
#item.UnitOfMeasure
#item.Ingredient
</p>
}
}
Related
The problem I'm facing now is I have multiple Orders and each Order contains multiple items. Each Order has to link to a Client and Each item has to link to a Inventory Item.
Here's my Order Class
public class Order
{
[Key]
public int Id { get; set; }
public int TotalItems { get; set; }
public DateTime DeliveryDate { get; set; }
public string OrderNumber { get; set; }
public int ClientId { get; set; }
[ForeignKey("ClientId")]
public string DeliveryAddress { get; set; }
public List<OrderItem> OrderItems { get; set; }
public Client Clients { get; set; }
}
OrderItem Class
public class OrderItem
{
public int Id { get; set; }
public int OrderId{ get; set; }
[ForeignKey("OrderId")]
public int InventoryInfoId { get; set; }
[ForeignKey("InventoryInfoId")]
[Required]
public string ItemCode { get; set; }
public int Quantity { get; set; }
public InventoryInfo InventoryInfo { get; set; }
public Order Order { get; set; }
}
Any idea of how I can link them?
I think I have solved the above issues
As soon as I process, the next problem pops out.
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(m => item.OrderNumber)
</td>
<td>
#Html.DisplayFor(m=> item.DeliveryAddress)
</td>
<td>
#Convert.ToDateTime(item.DeliveryDate).ToString("dd-MM-yyyy")
</td>
<td>
#Html.DisplayFor(m=>item.Client.ClientCode)
</td>
<td>
#Html.DisplayFor(modelItem => item.TotalItems)
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.Id" class="btn btn-success">Edit</a>
<a asp-controller="OrderItem" asp-action="OrderDetail" asp-route-id="#item.Id" class="btn btn-success">Details</a>
<a asp-action="Delete" asp-route-id="#item.Id" class="btn btn-success">Delete</a>
</td>
</tr>
}
This is my Orders Index page, when the details button is been clicked, the page should redirect to OrderItems page. However it doesnot.
#model List<IOSystem.Models.OrderItem>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(m => item.ItemCode)
</td>
<td>
#Html.DisplayFor(m => item.Quantity)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
#Html.ActionLink("Delete", "Delete", new { id = item.Id })
</td>
</tr>
}
And here is the error message.
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'System.Collections.Generic.List1[IOSystem.Models.Order]', but this ViewDataDictionary instance requires a model item of type 'System.Collections.Generic.List1[IOSystem.Models.OrderItem]'.
Forgot to add my controller
[HttpPost, ActionName("OrderDetail")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> OrderDetailPost(int? id)
{
if (id == null)
{
return NotFound();
}
var orderItems = await _context.Orders.Include(s=>s.OrderItems).FirstOrDefaultAsync(i => i.OrderItemId == id);
return View(orderItems);
}
Your InvalidOperationException is saying you're passing a List<Order> but the model in your Razor page is a List<OrderItem>
In your controller code:
[HttpPost, ActionName("OrderDetail")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> OrderDetailPost(int? id)
{
if (id == null)
{
return NotFound();
}
var orderItems = await _context.Orders.Include(s=>s.OrderItems).FirstOrDefaultAsync(i => i.OrderItemId == id);
return View(orderItems);
}
You're accessing _context.Orders, which is your Orders table. You're .Include-ing the OrderItems but you're returning your Orders.
Either pass back the OrderItems from var orderItems = ... or adjust your Razor page's Model to be a List<Order>.
If you want to select the OrderItems from your Order in the controller code, update your LINQ statement to:
var orderItems = (await _context.Order
.Include(s => s.OrderItems)
.FirstOrDefaultAsync(i => i.OrderItemId == id))
.Select(x => x.OrderItems); // <-- grab just the OrderItems
I'm creating a system which lists all of data employees and their email and ext etc. I've got this working fine with a search.
Model:
namespace ServiceDirectory.Models
{
[Table("Employee")]
public class Employee
{
[Key]
public int EmployeeID { get; set; }
[DisplayName("First Name")]
public String Forename { get; set; }
[DisplayName("Surname")]
public String Surname { get; set; }
public String Ext { get; set; }
public String Email { get; set; }
public bool Active { get; set; }
}
}
View:
#model IEnumerable<ServiceDirectory.Models.Employee>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm("Index", "Employee", FormMethod.Get))
{
<b>Search By:</b> #Html.RadioButton("searchBy", "Surname", true) <text>Surname</text>
#Html.RadioButton("searchBy", "Forename") <text>ForeName</text><br />
#Html.TextBox("search") <input type="submit" value="Search" />
}
<table class="table">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Ext</th>
<th scope="col">Job Title & Location</th>
<th scope="col">Email</th>
</tr>
</thead>
#foreach (var Employee in Model)
{
<tr>
<td>#Employee.Forename #Employee.Surname</td>
<td>#Employee.Ext</td>
<td>Job Title here</td>
<td>#Employee.Email</td>
</tr>
}
</table>
Controller:
namespace ServiceDirectory.Controllers
{
public class EmployeeController : Controller
{
private ApplicationDbContext db;
public EmployeeController()
{
db = new ApplicationDbContext();
}
// GET: Employee
public ActionResult Index(string searchBy, string search)
{
if (searchBy == "Forename")
{
return View(db.Employee.Where(x => x.Forename.StartsWith(search)).Where(e => e.Active).ToList());
}
else
{
return View(db.Employee.Where(x => x.Surname.StartsWith(search)).Where(e => e.Active).ToList());
}
}
protected override void Dispose(bool disposing)
{
db.Dispose();
}
}
}
In my view you will see "Job Title here", what I want to do is get the job title to display for each employee, my issue is that its in another table called EmployeeDetails.
How can I link into EmployeeDetails to get the job title and link it into my employee view?
Any help would be appreciated, this is my 1st project :)
First, create a class (view model) something like this below. You would list down the properties you want to display. I name it EmpVM
public class EmpVM
{
public int EmployeeID { get; set; }
public String Forename { get; set; }
public String Surname { get; set; }
public String Ext { get; set; }
public String Email { get; set; }
public bool Active { get; set; }
public String JobTitle { get; set; }
}
Then in your controller you use Linq join to join Employee table and Employee detail and push the result as EmpVM class
public ActionResult Index(string searchBy, string search)
{
List<EmpVM> Employee = new List<EmpVM>();
var Emp = (from E1 in db.Employee
join E2 in db.EmployeeDetail
on E1.EmployeeID equals E2.EmployeeId
select new EmpVM
{
EmployeeID = E1.EmployeeID,
Forename = E1.Forename,
Surname = E1.Surname,
Ext = E1.Ext,
Email = E1.Email,
Active = E1.Active,
JobTitle = E2.JobTitle
});
if (searchBy == "Forename")
{
Emp.Where(a => a.Forename.StartsWith(search) && a.Active == true);
}
else
{
Emp.Where(a => a.Surname.StartsWith(search) && a.Active == true);
}
Employee = Emp.ToList();
return View(Employee);
}
The view will be very simple. You just need to display the collection. It goes like (remember to replace your own namepsace)
#model IEnumerable<Incendo.Web.Models.EmpVM>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#*Your search method here*#
<table class="table table-condensed ">
#foreach (var item in Model)
{
<tr>
<td>#item.Forename #item.Surname</td>
<td>#item.Ext</td>
<td>#item.Email</td>
<td>#item.JobTitle</td>
</tr>
}
</table>
I have not tested it life but I think it should work. Let me know your result.
You can achieve by having a view model. I assume your EmployeeDetail class like below
public class EmployeeDetail
{
public int Id { get; set; }
public int EmployeeId { get; set; }
public string JobDescription { get; set; }
}
Create a ViewModel for the purpose and name it as EmployeeVM
public class EmployeeVM
{
public List<Employee> Employees { get; set; }
public List<EmployeeDetail> EmployeeDetails { get; set; }
}
In your Controller
public ActionResult Index(string searchBy, string search)
{
List<EmpVM> Employee = new List<EmpVM>();
var Emp = (from E1 in db.Employee
join E2 in db.EmployeeDetail
on E1.EmployeeID equals E2.EmployeeId
select new EmpVM
{
EmployeeID = E1.EmployeeID,
Forename = E1.Forename,
Surname = E1.Surname,
Ext = E1.Ext,
Email = E1.Email,
Active = E1.Active,
JobTitle = E2.JobTitle
});
if (searchBy == "Forename")
{
if (!String.IsNullOrEmpty(search))
{
Emp = Emp.Where(a => a.Forename.StartsWith(search) && a.Active == true);
}
}
else
{
if (!String.IsNullOrEmpty(search))
{
Emp = Emp.Where(a => a.Surname.StartsWith(search) && a.Active == true);
}
}
Employee = Emp.ToList();
return View(Employee);
}
In your View
#model IEnumerable<Incendo.Web.Models.EmpVM>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm())
{
<b>Search By:</b> #Html.RadioButton("searchBy", "Surname", true)
<text>Surname</text>
#Html.RadioButton("searchBy", "Forename") <text>ForeName</text>
<br />
#Html.TextBox("search")
<input type="submit" value="Search" />
}
<table class="table table-condensed ">
#foreach (var item in Model)
{
<tr>
<td>#item.Forename #item.Surname</td>
<td>#item.Ext</td>
<td>#item.Email</td>
<td>#item.JobTitle</td>
</tr>
}
</table>
How can I achieve the same result using my view Model
Model 1:
public class Unit
{
public int Id { get; set; }
[Required]
public string UnitName { get; set; }
public virtual ICollection<Staff> Staffs { get; set; }
}
Model 2:
public class Staff
{
public int Id { get; set; }
public string FullName { get; set; }
public int UnitId { get; set; }
public virtual Unit Unit { get; set; }
}
My ViewModel:
public class StaffVM
{
public int Id { get; set; }
public string FullName { get; set; }
public int UnitId { get; set; }
public string UnitName { get; set; }
}
Controller Index function:
// GET: Staffs
public ActionResult Index()
{
var query = from c in db.MyStaff
join d in db.MyUnit on c.UnitId equals d.Id
select new StaffVM
{
Id = c.Id,
FullName = c.FullName,
UnitName = d.UnitName
};
ViewBag.query = query;
return View();
}
My View Index view:
#model IEnumerable<MVC5WAuth.ViewModels.StaffVM>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.FullName)
</th>
<th>
Unit
</th>
<th></th>
</tr>
#foreach (var item in ViewBag.query) {
<tr>
<td>
#item.FullName
</td>
<td>
#item.UnitName
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
#Html.ActionLink("Details", "Details", new { id=item.Id }) |
#Html.ActionLink("Delete", "Delete", new { id=item.Id })
</td>
</tr>
}
</table>
Hi there I was looking for a way to select certain fields from the different database tables and output it into one table in the view.This is the code I have so far although it is only able to retrieve information from the patients table. Any help would be greatly appreciated thanks.
model
namespace ChampPMS.Models
{
public class Patient
{
public int PatientID { get; set; }
public string HouseChartNo { get; set; }
public string ClinicChartNo { get; set; }
public string Title { get; set; }
public string FirstName { get; set; }
public DateTime DOB { get; set; }
Dont think this is right.
//Other Table variables
public Admission ExpectedDate { get; set; } ------->from bed
public Beds Bed { get; set; } ------->from admissions
}
public class Beds
{
public int BedID { get; set; }
public int RoomID { get; set; }
public string Bed { get; set; }
}
public class Admission
{
public int AdmissionID { get; set; }
public int PatientID { get; set; }
public DateTime ExpectedDate { get; set; }
public int BedID { get; set; }
public string Phone { get; set; }
}
public PatientDBContext()
: base("PatientsDBContext")//connection string
{
}
public DbSet<Admission> Admission { get; set; }
public DbSet<Beds> Beds { get; set; }
public DbSet<Patient> Patient { get; set; }
}
view
#model IEnumerable<ChampPMS.Models.Patient>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create", null, new { #class = "btn btn-success" })
</p>
<table class="table table-condensed table-striped table-hover table-bordered ">
<tr>
<th>
#Html.DisplayNameFor(model => model.HouseChartNo)
</th>
<th>
#Html.DisplayNameFor(model => model.ClinicChartNo)
</th>
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
<th>
#Html.DisplayNameFor(model => model.FirstName)
</th>
<th>
#Html.DisplayNameFor(model => model.DOB)
</th>
<th>
#Html.DisplayNameFor(model => model.Bed)----->from bed table
</th>
<th>
#Html.DisplayNameFor(model => model.ExpectedDate)----->from admission table
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.HouseChartNo)
</td>
<td>
#Html.DisplayFor(modelItem => item.ClinicChartNo)
</td>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.FirstName)
</td>
<td>
#Html.DisplayFor(modelItem => item.SurName)
</td>
<td>
#Html.DisplayFor(modelItem => item.DOB)
</td>
<td>
#Html.DisplayNameFor(model => model.Bed)------->from bed table
</td>
<td>
#Html.DisplayNameFor(model => model.ExpectedDate) ----->from admission table
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.PatientID }, new { #class = "btn btn-xs btn-info" }) |
#Html.ActionLink("Details", "Details", new { id = item.PatientID }, new { #class = "btn btn-xs btn-primary" }) |
#Html.ActionLink("Delete", "Delete", new { id = item.PatientID }, new { #class = "btn btn-xs btn-danger" })
</td>
</tr>
}
</table>
Controller
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using ChampPMS.Models;
namespace ChampPMS.Controllers
{
public class PatientsController : Controller
{
private PatientDBContext db = new PatientDBContext();
// GET: Patients
public ActionResult Index()
{
return View(db.Patient.ToList());
}
// GET: Patients/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Patient patient = db.Patient.Find(id);
if (patient == null)
{
return HttpNotFound();
}
return View(patient);
}
// GET: Patients/Create
public ActionResult Create()
{
return View();
}
// POST: Patients/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 = "PatientID,HouseChartNo,ClinicChartNo,Title,FirstName,SurName,DOB,HouseName,Street,Town,County,Telephone,Mobile,Gender,Occupation,Marital,TaxNumber,GMSnumber,DPSnumber,ReligionID,Status,HashCode")] Patient patient)
{
if (ModelState.IsValid)
{
db.Patient.Add(patient);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(patient);
}
// GET: Patients/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Patient patient = db.Patient.Find(id);
if (patient == null)
{
return HttpNotFound();
}
return View(patient);
}
// POST: Patients/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 = "PatientID,HouseChartNo,ClinicChartNo,Title,FirstName,SurName,DOB,HouseName,Street,Town,County,Telephone,Mobile,Gender,Occupation,Marital,TaxNumber,GMSnumber,DPSnumber,ReligionID,Status,HashCode")] Patient patient)
{
if (ModelState.IsValid)
{
db.Entry(patient).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(patient);
}
// GET: Patients/Delete/5
public ActionResult Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Patient patient = db.Patient.Find(id);
if (patient == null)
{
return HttpNotFound();
}
return View(patient);
}
// POST: Patients/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
Patient patient = db.Patient.Find(id);
db.Patient.Remove(patient);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
}
Rather than return the data directly from the database to the View you should create a View-Model in the controller action.
This ViewModel would contain all of the information that you need to display.
Using a ViewModel ensures that only the data required for the View is returned. It means rendering your View is more simple and you can use data from many different sources in one single ViewModel.
I am trying to learn ASP.NET MVC (C#), and am currently tackling ViewModels. I understand the purpose of ViewModels, and I can get data through to the screen using them, but am having difficulties with understanding their relationship with - another new element for me - interfaces.
I want to achieve the following View:
You can see I have a simple initial insert form for adding a new staff member, with a dropdown for salutations. Following this, there is a second form for editing where I iterate through available staff members, placing their values into relevant input fields, where the salutation dropdown defaults to their relative salutation.
I have two Domain Models / tables, Prm_Staff and Prm_Salutation, which I am accessing (wrong word, I think) via the ViewModel Staff_VM:
public class Staff_VM
{
public int StaffID { get; set; }
public int SalutationID { get; set; }
public string FName { get; set; }
public string LName { get; set; }
public bool Active { get; set; }
public List<Prm_Salutation> AvailableSalutations { get; set; }
}
public class StaffMembers
{
public Staff_VM StaffVm;
public IEnumerable<Staff_VM> ListStaffVms;
}
In my controller:
var activeSalts = (from a in db.Prm_Salutations
where a.Active == true
orderby a.Desc ascending
select a).ToList();
var model = new StaffMembers
{
ListStaffVms = (from a in db.Prm_Staffs
where a.Active == true
orderby a.LName ascending
select new Staff_VM
{
StaffID = a.Prm_StaffID,
SalutationID = a.SalutationID,
FName = a.FName,
LName = a.LName,
Active = a.Active,
AvailableSalutations = activeSalts
}),
StaffVm = new Staff_VM()
{
AvailableSalutations = activeSalts
},
};
return View("StaffMembers", model);
In the View, I refer to that model #model November.ViewModels.StaffMembers:
#*Record New Staff Member*#
<tr>
<td>
#Html.DropDownListFor(
model => model.StaffVm.SalutationID,
Model.StaffVm.AvailableSalutations.Select(option => new SelectListItem
{
Text = option.Desc.ToString(),
Value = option.Prm_SalutationID.ToString()
}
),
"Choose...")
</td>
<td>#Html.EditorFor(model => model.StaffVm.FName)</td>
<td>#Html.EditorFor(model => model.StaffVm.LName)</td>
<td>#Html.EditorFor(model => model.StaffVm.Active)</td>
</tr>
#*Update Existing Staff Members*#
#foreach (var staff in Model.ListStaffVms)
{
<tr>
<td>#Html.HiddenFor(model => staff.StaffID)#Html.ValueFor(model => staff.StaffID) </td>
<td>
#Html.DropDownListFor(
model => staff.SalutationID, staff.AvailableSalutations.Select(option => new SelectListItem
{
Selected = (option.Prm_SalutationID == staff.SalutationID),
Text = option.Desc.ToString(),
Value = option.Prm_SalutationID.ToString()
}
),
"Choose...")
</td>
<td>#Html.EditorFor(model => staff.FName)</td>
<td>#Html.EditorFor(model => staff.LName)</td>
<td>#Html.EditorFor(model => staff.Active)</td>
<td>Delete</td>
</tr>
}
ActionResult:
public ActionResult UpdateStaff(StaffMembers list)
{
if (ModelState.IsValid)
{
foreach (var staffVm in list.ListStaffVms)
{
Prm_Staff staff = db.Prm_Staffs.Find(staffVm.StaffID);
staff.SalutationID = staffVm.SalutationID;
staff.FName = staffVm.FName;
staff.LName = staffVm.LName;
staff.Active = staffVm.Active;
}
db.SaveChanges();
ViewBag.rtrn = "Successfully Updated.";
return RedirectToAction("Parameters", new { param = "Staff Members", rtrn = ViewBag.rtrn });
}
else
{
ViewBag.rtrn = "Failed ! Please try again.";
return RedirectToAction("Parameters", new { param = "Staff Members", rtrn = ViewBag.rtrn });
}
}
EDIT: Updated to show most recent changes
I think you should consider change your ViewModel. Also do something like below:
ViewModel
public class Staff_VM
{
public int ID { get; set; }
public int SalutationID { get; set; }
public string FName { get; set; }
public string LName { get; set; }
public bool Active { get; set; }
}
public class MyViewModel
{
public Staff_VM StaffVm { get; set; }
public List<Staff_VM> ListStaffVms { get; set; }
public List<Prm_Salutation> AvailableSalutations { get; set; }
}
Add_Update_Staff Action
[HttpGet]
public ActionResult Add_Update_Staff()
{
var model = new MyViewModel
{
ListStaffVms = (from a in db.Prm_Staffs
where a.Active == true
orderby a.LName ascending
select new Staff_VM
{
ID = a.Id,
SalutationID = a.SalutationID,
FName = a.FName,
LName = a.LName,
Active = a.Active
}),
AvailableSalutations = (from p in db.Prm_Salutations
where a.Active == true
orderby p.Desc ascending
select p).ToList()
};
return View(model);
}
Update Staff Post
[HttpPost]
public ActionResult Add_Update_Staff(MyViewModel model, string buttonType)
{
if (buttonType == "Insert")
{
if (ModelState.IsValid)
{
//save a new staff info
return RedirectToAction("Index", "Home");
}
}
if (buttonType == "Update")
{
foreach (var staffVm in model.ListStaffVms)
{
// update each record here
}
return RedirectToAction("Index", "Home");
}
model.AvailableSalutations = (from p in db.Prm_Salutations
orderby p.Desc ascending
select p).ToList();
return View(model);
}
View
You may need to add validation for insert and update staff info
#using (Html.BeginForm("Add_Update_Staff", "Staff"))
{
<tr>
<td>
#Html.DropDownListFor(
model => model.StaffVm.SalutationID, Model.AvailableSalutations.Select(option => new SelectListItem
{
Text = option.Desc.ToString(),
Value = option.Prm_SalutationID.ToString()
}
), "Choose...")
</td>
<td>#Html.EditorFor(model => model.StaffVm.FName)</td>
<td>#Html.EditorFor(model => model.StaffVm.LName)</td>
<td>#Html.EditorFor(model => model.StaffVm.Active)</td>
</tr>
<input type="submit" value="Insert" name="buttonType" />
for (int i = 0; i < Model.ListStaffVms.Count(); i++)
{
<tr>
<td>#Html.HiddenFor(m => m.ListStaffVms[i].ID)#Html.ValueFor(m => m.ListStaffVms[i].ID) </td>
<td>
#Html.DropDownListFor(
m => m.ListStaffVms[i].SalutationID, Model.AvailableSalutations.Select(option => new SelectListItem
{
Selected = (option.Prm_SalutationID == Model.ListStaffVms[i].SalutationID),
Text = option.Desc.ToString(),
Value = option.Prm_SalutationID.ToString()
}), "Choose...")
</td>
<td>#Html.EditorFor(model => model.ListStaffVms[i].FName)</td>
<td>#Html.EditorFor(model => model.ListStaffVms[i].LName)</td>
<td>#Html.EditorFor(model => model.ListStaffVms[i].Active)</td>
<td>Delete</td>
<hr />
</tr>
}
<input type="submit" value="Update" name="buttonType" />
}