i have many to many relationship between faxes and employees
I wanna have a fax form which has a listBox to select employees but i don't know how get the selected employees
FaxForm.cshtml:
#using (Html.BeginForm("CreateFax", "Fax"))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Fax.Courier_Num, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Fax.Courier_Num, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Fax.Courier_Num)
</div>
</div>
<div class="form-group">
<div class="col-md-10">
#Html.ListBox("Employees", ViewBag.Employees as MultiSelectList,
new { #class = "chzn-select", data_placeholder = "Choose Employee..." })
</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>
FaxController.cs:
public ActionResult New()
{
var Employees = Db.Employees;
ViewBag.Employees = new MultiSelectList(Employees, "Id", "Name");
return View("FaxForm");
}
public ActionResult CreateFax(Fax fax)
{
if (!ModelState.IsValid)
{
//some Code
return View("FaxForm"/*, viewModel*/);
}
if (fax.Id == 0)
{
Db.Faxes.Add(fax);
Db.SaveChanges();
}
return RedirectToAction("Index", "Employees");
}
i create viewmodel class to make relation between employees and faxes
MenuViewModel.cs:
public IEnumerable<SelectListItem> Employees { set; get; }
public Fax Fax { set; get; }
i need to save the selected employees in fax table..........................
You should use a view model specific to your view. Do not mix your entity model with that.
public class SendFaxVm
{
public List<SelectListItem> Employees { set; get; }
public int[] SelectedEmployees { set; get; }
public string CompanyName { set; get; }
public string CompanyAddress { set; get; }
// To do : Add other properties needed in the VIEW
}
Now in your GET action, create an object of this, load the Employees property and send it to the view
public ActionResult New()
{
var vm= new SendFaxVm();
vm.Employees = db.Employees
.Select(a => new SelectListItem() {Value = a.Id.ToString(),
Text = a.Name})
.ToList();
return View(vm);
}
Now in your view, which is strongly typed to our SendFaxVm, use the helper methods to generate your textbox's and multi select dropdown
#model SendFaxVm
#using (Html.BeginForm("CreateFax", "Fax"))
{
#Html.TextBoxFor(a => a.CompanyName)
#Html.TextBoxFor(a => a.CompanyAddress)
#Html.ListBoxFor(a => a.SelectedEmployees, Model.Employees)
<input type="submit" />
}
And use the same view model as the parameter of your HttpPost action method. When the form is submitted the properties will be populated by the data sent from the form. The SelectedEmployees property will be an array of UserId's which was selected. You can read these property values and save it to your entity tables.
[HttpPost]
public ActionResult CreateFax(SendFaxVm model)
{
// check model.SelectedEmployees and other properties
// and use that to save data to your tables
Fax f=new Fax();
f.CompanyName = model.CompanyName;
f.CompanyAddress = model.CompanyAddress;
// to do : Assign other property values for the Fax table
db.Fax.Add(f);
db.SaveChanges();
//Now loop through the SelectedEmployees and save record for FaxData table
foreach(var userId in model.SelectedEmployees)
{
var fd=new FaxData { EmpId = userId, FaxId=f.Id };
//to do : Save fd
}
return RedirectToAction("Index");
}
Related
I am trying to post multiselect option and save it in Db. I did try few options but same did not work.
Client model class:
public string OwnerName { get; set; }
public string UnitNumber { get; set; }
public int AreaId { get; set; } // This is a foreign key
public string AreaName { get; set; } // This will display dropdown list
Controller action method - I am using FormCollection to collect the AreaId from the view to post in Client model class:
public ActionResult ClientDeal(Client model, FormCollection formCollection)
{
string selectedArea = formCollection["AreaId"];
}
Here is the view with the field I am having trouble with
<div class="form-group col-md-4">
<label class="control-label col-md-8 font-weight-bold">Area</label>
<div class="col-md-10">
#Html.DropDownListFor(model => model.AreaId, Model.Areas, new { #class = "form-control selectpicker select", #multiple = "multiple" })
#Html.ValidationMessageFor(model => model.Areas, "", new { #class = "text-danger" })
</div>
</div>
Thank you in advance
this line is wrong:
#Html.DropDownListFor(model => model.AreaId, Model.Areas, new { #class = "form-control selectpicker select", #multiple = "multiple" })
You need to bind the dropdown to a collection property, have something like:
public int[] AreaIds { get; set; }
and bind it like this:
#Html.DropDownListFor(model => model.AreaIds,
There's no need to set the value Model.Areas in the helper declaration, just set in the ViewModel when you return the view:
return View(new Client { AreaIds = "what you now have in Model.Areas" }
There's no need to use FormCollection
I'm adding dynamically items to an Enquiry form. Used partial view to for adding/deleting the items but while submitting the main view the values are not bound. My question is how to do the same.
Have checked couple of similar questions here and here But could not find what's missing .
Using 2 ViewModels , for Main View ( Enquiry) and for partial view ( LineItems) and used BeginCollectionItem for dynamically adding items.
Code:
ViewModels
public class EnquiryVM
{
public int ID { get; set; }
[Required]
public string EnquiryNumber { get; set; }
public int ClientID { get; set; }
public IEnumerable<SelectListItem> Clients { get; set; }
public Client Client { get; set; }
public int ItemID { get; set; }
public List<EnquiryLineItem> LineItems { get; set; }
}
public class EnquiryLineItemVM
{
public int ID { get; set; }
[Required]
public string ItemDesc { get; set; }
public int Quantity { get; set; }
public int ManufacturerId { get; set; }
public IEnumerable<SelectListItem> ManufacturerList { get; set; }
}
Views :
Main:
#model ViewModel.EnquiryVM
#using (Html.BeginForm("Create", "Enquiries", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.EnquiryNumber, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-3">
#Html.EditorFor(model => model.EnquiryNumber, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.EnquiryNumber, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ClientID, "Client", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-3">
#Html.DropDownListFor(u => u.ClientID, (IEnumerable<SelectListItem>)Model.Clients, "--Select--")
#Html.ValidationMessageFor(model => model.ClientID, "", new { #class = "text-danger" })
</div>
</div>
<div id="LineItems">
// #using (Html.BeginForm()) // do we require again here since this will be like nested form? tested commenting still not working
// {
<div id="editorRowsLineitems">
#foreach (var item in Model.LineItems)
{
#Html.Partial("_CreateEnquiryItem", item)
}
</div>
#Html.ActionLink("Add Items", "CreateLineItem", null, new { id = "addItem", #class = "button" });
// }
</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>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript">
$(function () {
$('#addItem').on('click', function () {
$.ajax({
url: '#Url.Action("CreateLineItem")',
cache: false,
success: function (html) {
$("#editorRowsLineitems").append(html);
$("form").removeData("validator");
$("form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("form");
}
});
return false;
});
$('#editorRowsLineitems').on('click', '.deleteRow', function () {
$(this).closest('.editorRow').remove();
});
$('form').data('validator', null);
$.validator.unobtrusive.parse($('form'));
});
</script>
}
partial view :
#model ViewModels.EnquiryLineItemVM
<div class="editorRow">
#using (Html.BeginCollectionItem("ItemList"))
{
<table class="table">
<tr>
<td>
#Html.EditorFor(model => model.ItemDesc)
</td>
<td>
#Html.EditorFor(model => model.Quantity)
</td>
<td>
#Html.DropDownListFor(model => model.ManufacturerId, Model.ManufacturerList, "--Please Select--")
</td>
<td>
Delete
</td>
</tr>
</table>
}
Controller :
public ActionResult Create()
{
var viewModel = GetAllCategories();
return View(viewModel);
}
private EnquiryVM GetAllCategories()
{
var model = new EnquiryVM();
var clients = db.Clients.ToList();
model.Clients = clients.Select(s => new SelectListItem
{
Value = s.ID.ToString(),
Text = s.Name
});
var LineItems = new List<EnquiryLineItem>();
model.LineItems = LineItems;
return model;
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create( EnquiryVM enquiryVM)
{
var enquiry = new Enquiry();
enquiry.EnquiryNumber = enquiryVM.EnquiryNumber;
enquiry.ClientID = enquiryVM.ClientID;
enquiry.EnquiryLineItems = enquiryVM.LineItems; //line items are null
if (ModelState.IsValid)
{
db.Enquiries.Add(enquiry);
enquiryVM.ID = enquiry.ID;
foreach (var item in enquiry.EnquiryLineItems)
{
item.EnquiryID = enquiryVM.ID;
db.EnquiryLineItems.Add(item);
}
db.SaveChanges();
return RedirectToAction("Index");
}
var viewModel = GetAllCategories();
return View(enquiryVM);
}
How shall I map the dynamically added row's values to the ViewModel ( EnquiryVM ) so that I can insert it into the DB.
Thanks for your patience and time.
The name of your collection property is LineItems, therefore your code to generate its controls needs to be
#using (Html.BeginCollectionItem("LineItems")) // not ..("ItemList")
{
....
}
so that it generates inputs with name="LineItems[xxxx].ItemDesc" etc, rather than your current use which generates name="ItemList[xxxx].ItemDesc" (where xxxx is the Guid)
As a side note, the code in your POST method will throw an exception if ModelState is invalid because you return the view and have not repopulated the IEnumerable<SelectListItem> Clients property. Refer The ViewData item that has the key 'XXX' is of type 'System.Int32' but must be of type 'IEnumerable' for a detailed explanation.
In addition, the final 2 lines of your script to add items ($('form').data('validator', null); $.validator.unobtrusive.parse($('form')); should be removed (reparsing the validator is expensive and your doing it twice - once before you add the html (the 2 lines above) and once after you add the html
This question already has answers here:
Pass List of Checkboxes into View and Pull out IEnumerable [duplicate]
(2 answers)
Closed 6 years ago.
I need to populate a checkbox list of equipment on a form for users to request equipment. The data for the list is stored in a table named 'Equipment'. I am working with EF 6 database first. The view is strongly typed and will write to an 'Orders' table. I am stuck on how to use a View Model and not ViewBag to populate the check box list for the form. I have looked at MikesDotNetting, the Rachel Lappel post about view models and several others and it's not making sense to me.
Code below:
public class Equipment
{
public int Id { get; set; }
public string Description { get; set; }
public string Method { get; set; }
public bool Checked { get; set; }
}
public class Order
{
public int id{ get; set; }
public string Contact_Name { get; set; }
public List<Equipment>Equipments { get; set; }
public string Notes { get; set; }
}
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Contact_Name,Equipment,Notes")] Order order)
{
if (ModelState.IsValid)
{
db.Orders.Add(order);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(order);
}
View
#model CheckBoxList.Models.Order
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Order</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Contact_Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Contact_Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Contact_Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
//checkbox list populated here
</div>
<div class="form-group">
#Html.LabelFor(model => model.Notes, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Notes, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Notes, "", new { #class = "text-danger" })
</div>
</div>
See this answer for how to do it How to bind checkbox values to a list of ints?
That example uses Guid's as PK's but that can be easily replaced with int's.
I'm going to assume your Equipment class is your EF entity.
So you are creating your order page so let's start with the CreateOrderViewModel
public class CreateOrderViewModel
{
public string Contact_Name { get; set; }
public Dictionary<int, string> AllEquipment{ get; set; }
public int[] SelectedEquipment { get;set; }
public string Notes { get; set; }
}
Populate AllEquipment with just the id and the name of the piece of equipment. This is the complete list of equipment that will be needed to show all the equipment checkboxes with the value of the id of the equipment.
Something like
var viewModel = new CreateOrderViewModel {
AllEquipment = context.Equipment.ToDictionary(e => e.Id, e.Description);
}
SelectedEquipment is the list of equipment with checkboxes checked. So when you post this information back, the SelectedEquipment property will have a list of all the id's that need to be attached to the order.
When you create the order just iterate through the list and add them to the Equipment list in your Order entity.
Make a for loop in your list and generate a checkbox for every item in it.
<div class="form-group">
#for (int i = 0; i < Model.Equipments.Count(); i++)
{
#Html.CheckBoxFor(x => x.Equipments[i].Checked)
#Model.Equipments[i].Description
//If you need to hide any values and get them in your post
#Html.HiddenFor(x => x.Equipments[i].Id)
#Html.HiddenFor(x => x.Equipments[i].Method)
}
</div>
I appear to be having some problems with dropdown list populating and binding in MVC. The simple example I have has a List of Movies with a Genre item that is populated with a drop down.
I pass across a Select List with the items to populate the drop down but appear to be running into problems when the post action is happening.
The problems appear to be :
The ViewModel being returned appears to return the GenreList as null on the Post action.
The Genre does not appear to be set so that after the edit -the dropdown list is populated correctly.
I cannot seem to find a good answer for this and have been trying quite a few examples but seem to be going round in circles. Would like to try and get this most basic of dropdown list edit example working so I can see how this should be implemented.
Model Classes
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Web;
namespace Test.Models
{
public class Genre
{
[Key]
public int Id { get; set; }
public string Description { get; set; }
}
public class Movie
{
[Key]
public int MovieID { get; set; }
public string Name { get; set; }
public Genre MovieGenre { get; set; }
}
public class MovieViewModel
{
public Movie MovieItem { get; set; }
public SelectList GenreList{ get; set; }
}
}
Controller Code
namespace Test.Controllers
{
public class MoviesController : Controller
{
private DataContext _dc = new DataContext();
// GET: Movies
public ActionResult Index()
{
var x = from m in _dc.Movies
select m;
return View(x.ToList());
}
// GET: Movies/Edit/5
public ActionResult Edit(int id)
{
var x = from m in _dc.Movies
where m.MovieID == id
select m;
var l = from m in _dc.Genres
select m;
var y = new MovieViewModel
{
GenreList = new SelectList(l.ToList(), "ID", "Description"),
MovieItem = x.FirstOrDefault()
};
return View(y);
}
// POST: Movies/Edit/5
[HttpPost]
public ActionResult Edit(int id, MovieViewModel m)
{
// PROBLEM: GenreList in model is now not populate for return
if (ModelState.IsValid)
{
var movie = _dc.Movies.Find(id);
movie.Name = m.MovieItem.Name;
movie.MovieGenre = m.MovieItem.MovieGenre;
// PROBLEM: The MovieGenre does not appear to be saved correctly
// when you make the edit and go back to that record after saving
// the dropdown is not populated.
_dc.SaveChanges();
return RedirectToAction("Index", "Movies");
}
return View(m);
}
}
}
Razor View Code
#model Test.Models.MovieViewModel
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Movie</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.MovieItem.MovieID)
<div class="form-group">
#Html.LabelFor(model => model.MovieItem.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.MovieItem.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.MovieItem.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div>
#Html.LabelFor(m => m.GenreList, "Genre:")
#Html.DropDownListFor(m => m.MovieItem.MovieGenre.Id, (IEnumerable<SelectListItem>) Model.GenreList)
</div>
</div>
<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 question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 7 years ago.
I'm still learning MVC and am confused. I am converting a windows application for CRUD with a database to an MVC website. I got an entire ViewModel's CRUD working that uses dropdownlist's already and the code is identical but throwing object reference not set errors with it in another page.
Controller
public ActionResult Create()
{
var shiftsEmployees = new ShiftsEmployeesViewModel();
var oEmployees = new CEmployees();
oEmployees.GetActiveEmployees();
shiftsEmployees.Employees = oEmployees;
return View(shiftsEmployees);
}
// POST: Shifts/Create
[HttpPost]
public ActionResult Create(ShiftsEmployeesViewModel shiftsEmployees)
{
try
{
shiftsEmployees.InsertShift();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
View
#model StatTracker.ASPMVC.ViewModels.ShiftsEmployeesViewModel
#{
ViewBag.Title = "Add Shift";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal text-center">
#Html.ValidationSummary(true, "", new {#class = "text-danger"})
<div class="form-group">
<div class="input-group date col-md-12">
#Html.LabelFor(model => model.Shift.Date, new {#class = "control-label"})
#Html.EditorFor(model => model.Shift.Date, new {#class = "form-control datepicker", placeholder = "Pick a date"})
#Html.ValidationMessageFor(model => model.Shift.Date, "", new {#class = "text-danger"})
#Html.LabelFor(model => model.Employee.FullName, new {#class = "control-label"})
#Html.DropDownListFor(model => model.Employee.Id, new SelectList(Model.Employees.Employees, "Id", "FullName", Model.Employee), null, null)
#Html.ValidationMessageFor(model => model.Employee.Id, "", new {#class = "text-danger"})
#Html.LabelFor(model => model.Shift.Hours, new {#class = "control-label"})
#Html.EditorFor(model => model.Shift.Hours, new {#class = "form-control", placeholder = "Hours worked"})
#Html.ValidationMessageFor(model => model.Shift.Hours, "", new {#class = "text-danger"})
</div>
</div>
<div class="form-group">
<div class="col-md-12">
<input type="submit" value="Add Shift" class="btn btn-default"/>
</div>
</div>
</div>
}
<div class="text-center col-md-12">
#Html.ActionLink("Back to List", "Index")
</div>
ViewModel:
namespace StatTracker.ASPMVC.ViewModels
{
public class ShiftsEmployeesViewModel
{
public CShift Shift { get; set; }
public CEmployee Employee { get; set; }
public CEmployees Employees { get; set; }
public void InsertShift()
{
CShift.InsertShift(hours: Shift.Hours, employeeid: Employee.Id, date: Shift.Date);
}
public void UpdateShift()
{
CShift.UpdateShift(hours: Shift.Hours, employeeid: Employee.Id, date: Shift.Date, shiftid: Shift.Id);
}
}
}
working code with same idea
controller
public ActionResult Create()
{
var oSalesEmployeeService = new SalesEmployeeServiceViewModel();
var oServices = new CServices();
oServices.GetServices();
var oEmployees = new CEmployees();
oEmployees.GetActiveEmployees();
oSalesEmployeeService.Employees = oEmployees;
oSalesEmployeeService.Services = oServices;
return View(oSalesEmployeeService);
}
// POST: Sales/Create
[HttpPost]
public ActionResult Create(SalesEmployeeServiceViewModel oSalesEmployeeService)
{
try
{
oSalesEmployeeService.InsertSale();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
viewmodel
using StatTracker.BL;
namespace StatTracker.ASPMVC.ViewModels
{
public class SalesEmployeeServiceViewModel
{
public CSale Sale { get; set; }
public CEmployees Employees { get; set; }
public CServices Services { get; set; }
public CEmployee Employee { get; set; }
public CService Service { get; set; }
public void InsertSale()
{
CSale.InsertSale(service: Service.Id, date: Sale.Date, employee: Employee.Id);
}
public void UpdateSale()
{
CSale.UpdateSale(service: Service.Id, date: Sale.Date, employee: Employee.Id, salesid: Sale.Id);
}
}
}
view
#model StatTracker.ASPMVC.ViewModels.SalesEmployeeServiceViewModel
#{
ViewBag.Title = "Add Sale";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal text-center">
#Html.ValidationSummary(true, "", new {#class = "text-danger"})
<div class="form-group">
<div class="input-group date col-md-12">
#Html.LabelFor(model => model.Sale.Date, new {#class = "control-label"})
#Html.EditorFor(model => model.Sale.Date, new {#class = "form-control datepicker", placeholder = "Pick a date"})
#Html.ValidationMessageFor(model => model.Sale.Date, "", new {#class = "text-danger"})
#Html.LabelFor(model => model.Employee.FullName, new {#class = "control-label"})
#Html.DropDownListFor(model => model.Employee.Id, new SelectList(Model.Employees.Employees, "Id", "FullName", Model.Employee), null, null)
#Html.ValidationMessageFor(model => model.Employee.Id, "", new {#class = "text-danger"})
#Html.LabelFor(model => model.Service.Description, new {#class = "control-label"})
#Html.DropDownListFor(model => model.Service.Id, new SelectList(Model.Services.Services, "Id", "Description", Model.Service), null, null)
#Html.ValidationMessageFor(model => model.Service.Id, "", new {#class = "text-danger"})
</div>
</div>
<div class="form-group">
<div class="col-md-12">
<input type="submit" value="Add Sale" class="btn btn-default"/>
</div>
</div>
</div>
}
<div class="text-center col-md-12">
#Html.ActionLink("Back to List", "Index")
</div>
You have not indicated exactly where the error is being thrown but there will be numerous reasons
Firstly, a view model is not just a holder for a series of data models. It should contain only those properties which you need to display/edit in the view. Currently if any properties of CShift or CEmployee have validation attributes (other that the Date and Hours properties), your model will be invalid.
Secondly, when you return the view, you need to return the model to the view and also assign the value of Employees which currently will be null (hence the exception when you access Model.Employees.Employees in the DropDownList() method).
Based on the view you have shown, your view model should be just (add validation attributes as required)
public class ShiftsEmployeesViewModel
{
public DateTime Date { get; set; }
public int Employee { get; set; }
public float Hours { get; set; }
public SelectList EmployeeList { get; set; }
}
Controller
public ActionResult Create()
{
ShiftsEmployeesViewModel model = new ShiftsEmployeesViewModel();
model.Employee = ? // set default selection
ConfigureCreateModel(model);
return View(model);
}
[HttpPost]
public ActionResult Create(ShiftsEmployeesViewModel model)
{
if (!ModelState.IsValid)
{
ConfigureCreateModel(model);
return View(model);
}
.... // map the view model properties to a new instance of the data model, save and redirect
}
private void ConfigureCreateModel(ShiftsEmployeesViewModel model)
{
var oEmployees = (new CEmployees()).GetActiveEmployees();
model.EmployeeList = new SelectList(oEmployees, "Id", "FullName");
}
View
#Html.LabelFor(m => m.Date)
#Html.TextBoxFor(m => m.Date)
#Html.ValidationMessageFor(m => m.Date)
#Html.LabelFor(m => m.Employee)
#Html.DropDownListFor(m => m.Employee, Model.EmployeeList, "-please select-")
#Html.ValidationMessageFor(m => m.Employee)
#Html.LabelFor(m => m.Hours)
#Html.EditorFor(m => m.Hours)
#Html.ValidationMessageFor(m => m.Shift.Hours)
Side note: Your current usage of SelectList(Model.Employees.Employees, "Id", "FullName", Model.Employee) where you use the 4th parameter is pointless. Your binding to a property, so attempting to set the value of the Selected is ignored (the selected option is based on the value of the property your binding to)
Yes, because model.Employee has not been initialized and therefore, model.Employee.Id will throw a null reference exception. After that You still need to initialize the shift object as it will also throw a null reference exception when model.Shift.Hours is accessed. Please see my suggestions below
You will have to initialize the remaining properties
public ActionResult Create()
{
var oEmployees = new CEmployees();
oEmployees.GetActiveEmployees();
var shiftsEmployees = new ShiftsEmployeesViewModel
{
Employee = new CEmployee(),
Shift = new CShift(),
Employees = oEmployees;
};
return View(shiftsEmployees);
}
Another option is to just always initialize them in the constructor of the view model (you just have to make sure that somewhere GetActiveEmployees is getting called)
public class ShiftsEmployeesViewModel
{
public ShiftsEmployeesViewModel()
{
this.oEmployees = new CEmployees();
this.Employee = new CEmployee();
this.Shift = new CShift();
}
}
Also change the implementation in your view for the dropdownlist
#Html.DropDownListFor(model => model.Employee.Id,
new SelectList(Model.Employees.Employees ?? new List<CEmployee>(),
"Id",
"FullName"))