I have a View:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="input-group">
<div class="input-group-addon">
#Html.Label("Employee number", new { #class = "control-label" })
</div>
<div class="a">
#Html.TextBoxFor(model => model.EmployeeNo, new {#class="form-control" })
#Html.ValidationMessageFor(model => model.EmployeeNo)
</div>
</div>
/*
* other fields
*/
}
and Controller:
[HttpPost]
public ActionResult Edit([Bind(Include="Id,EmployeeNo,Name,Surname,ContactInfo,RoleId")] User user)
{
ValidateRequestHeader(Request);
if (ModelState.IsValid)
{
unitOfWork.userRepository.Update(user);
unitOfWork.Save();
return Json(new { ok = true, newurl = Url.Action("Index") });
}
//ModelState.AddModelError("", "Niepoprawne dane");
ViewBag.RoleId = new SelectList(unitOfWork.roleRepository.Get(), "Id", "RoleName", user.RoleId);
return PartialView(user);
}
and model:
public partial class User
{
public User()
{
this.DeviceUsages = new HashSet<DeviceUsage>();
}
public int Id { get; set; }
[Required(ErrorMessage="Brak numeru pracownika")]
public string EmployeeNo { get; set; }
[Required(ErrorMessage = "Brak imienia")]
public string Name { get; set; }
[Required(ErrorMessage = "Brak nazwiska")]
public string Surname { get; set; }
[Required(ErrorMessage = "Brak Adresu email")]
public string ContactInfo { get; set; }
public int RoleId { get; set; }
}
Data annotations are working. If I leave eg. Name empty ModelState is not Valid in controler. But validation messages are not shown. If I uncomment this line:
ModelState.AddModelError("", "Niepoprawne dane"); this will be the only Model error shown in the View.
Where is a mistake in my code?
It's because you are using #Html.ValidationSummary(true) means excludePropertyErrors = true
Related
Please I need some help, on the adding new movie. I am facing an issue with [HttpPost] and I really don't know if it from it or not, but when I remove [HttpPost] the page is working.
My NewMovie View:
#model Vildy4.ViewModels.MovieFormViewModel
#{
ViewBag.Title = "NewMovie";
}
<h2>New Movie</h2>
#using (Html.BeginForm("NewMovie", "Movies"))
{
<div class="form-group">
#Html.LabelFor(m => m.Name)
#Html.TextBoxFor(m => m.Name, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(m => m.ReleaseDate)
#Html.TextBoxFor(m => m.ReleaseDate, "{0: d MMM yyyy}", new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(m => m.Genres)
#Html.DropDownListFor(m => m.GenresId, new SelectList(Model.Genres, "Id", "Name"), "Select Genre", new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(m => m.NumberInStock)
#Html.TextBoxFor(m => m.NumberInStock, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.NumberInStock)
</div>
#Html.HiddenFor(m => m.Id)
<button type="submit" class="btn btn-primary">Save</button>
}
My Action:
[HttpPost]
public ActionResult NewMovie(Movie movie)
{
if (!ModelState.IsValid)
{
var viewModel = new MovieFormViewModel(movie)
{
Genres = _context.Genres.ToList()
};
return View("NewMovie", viewModel);
}
if (movie.Id == 0)
{
movie.DateAdded = DateTime.Now;
_context.Movies.Add(movie);
}
else
{
var movieInDb = _context.Movies.Single(m => m.Id == movie.Id);
{
movieInDb.Name = movie.Name;
movieInDb.Genre = movie.Genre;
movieInDb.ReleaseDate = movie.ReleaseDate;
movieInDb.DateAdded = movie.ReleaseDate;
movieInDb.NumberInStock = movie.NumberInStock;
}
}
_context.SaveChanges();
return RedirectToAction("Index", "Movies");
}
Error:
Server Error in '/' Application.
The resource cannot be found.
Description:HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /Movies/NewMovie
When I remove [HttpPost] it is working normally, but I can not post.
I checked many threads (e.g. asp.net mvc 4 [HttpPost] not working) but it does not solve the issue.
I have another Controller with almost the same action and it works perfect.
Movie model:
public class Movie
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
[Required]
public string Genre { get; set; }
[Display(Name = "Genre")]
[Required]
public byte GenresId { get; set; }
[DisplayFormat(DataFormatString = "{0:d}")]
public DateTime ReleaseDate { get; set; }
[DisplayFormat(DataFormatString = "{0:d}")]
public DateTime DateAdded { get; set; }
[Required]
[Range(1,20)]
public int NumberInStock { get; set; }
}
MovieFormViewModel code:
public class MovieFormViewModel
{
public IEnumerable<Genre> Genres { get; set; }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int? Id { get; set; }
[Required]
[StringLength(255)]
public string Name { get; set; }
[Display(Name = "Genre")]
[Required]
public byte? GenresId { get; set; }
[Display(Name = "Release Date")]
[Required]
public DateTime? ReleaseDate { get; set; }
[Display(Name = "Number in Stock")]
[Range(1, 20)]
[Required]
public int? NumberInStock { get; set; }
public string Title
{
get
{
return Id != 0 ? "Edit Movie" : "New Movie";
}
}
public MovieFormViewModel()
{
Id = 0;
}
public MovieFormViewModel(Movie movie)
{
Id = movie.Id;
Name = movie.Name;
ReleaseDate = movie.ReleaseDate;
NumberInStock = movie.NumberInStock;
GenresId = movie.GenresId;
}
}
Here is the Headers:
Request URL: http://localhost:3593/Movies/NewMovie
Request Method: GET
Status Code: 404 Not Found
Remote Address: [::1]:3593
Referrer Policy: no-referrer-when-downgrade
here is also the route in my application, which is the default route:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
on the Source Page after getting the error, I noticed that I am getting the below Exception:
[HttpException]: A public action method 'NewMovie' was not found on controller 'Vildy4.Controllers.MoviesController'.
I also searched but I could not find the solution, because action is there in the controller and when i do [HttpGet] it is working only [HttpPost] not working!
I'm having trouble understanding how to retrieve data from my Device table in my database to a CheckBoxList.
I believe I have the Models, ViewModel and Database setup properly but I'm just not sure what to do next. For now, I would simple like to learn how to retrieve the data from my table to a CheckBoxList.
Customer Model
public class Customer
{
public int CustId { get; set; }
public string CustDisplayName { get; set; }
public string CustFirstName { get; set; }
public string CustLastName { get; set; }
public string CustCompanyName { get; set; }
public string CustAddress { get; set; }
public string CustPhoneNumber { get; set; }
public string CustMobileNumber { get; set; }
public string CustEmailAddress { get; set; }
public int StId { get; set; }
public State State { get; set; }
}
State Model
public class State
{
public int StId { get; set; }
public string StAbbr { get; set; }
public List<Customer> Customers { get; set; }
}
Device Model
public class Device
{
public int DevId { get; set; }
public string DevType { get; set; }
public bool isChecked { get; set; }
}
CustomerDevice Model
public class CustomerDevice
{
public int CustId { get; set; }
public int DevId { get; set; }
public Customer Customer { get; set; }
public Device Device { get; set; }
}
CustomerViewModel
public class CustomerFormViewModel
{
public int CustId { get; set; }
[Required(ErrorMessage = "Enter Display Name")]
[Display(Name = "Display Name")]
[StringLength(100)]
public string CustDisplayName { get; set; }
[Display(Name = "First Name")]
[StringLength(50)]
public string CustFirstName { get; set; }
[Display(Name = "Last Name")]
[StringLength(50)]
public string CustLastName { get; set; }
[Display(Name = "Company Name")]
[StringLength(50)]
public string CustCompanyName { get; set; }
[Display(Name = "Phone Number")]
[DataType(DataType.PhoneNumber)]
[StringLength(12)]
public string CustPhoneNumber { get; set; }
[Display(Name = "Mobile Number")]
[DataType(DataType.PhoneNumber)]
[StringLength(12)]
public string CustMobileNumber { get; set; }
[Display(Name = "Email Address")]
[DataType(DataType.EmailAddress)]
[StringLength(320)]
public string CustEmailAddress { get; set; }
[Required(ErrorMessage = "Enter Address")]
[Display(Name = "Address")]
[StringLength(100)]
public string CustAddress { get; set; }
[Required(ErrorMessage = "Select State")]
[Display(Name = "State")]
public int StId { get; set; }
public IEnumerable<State> States { get; set; }
}
CustomerController
public class CustomerController : Controller
{
private CoreWebAppContext _context;
public CustomerController(CoreWebAppContext context)
{
_context = context;
}
// GET: /<controller>/
public IActionResult Index()
{
return View(_context.Customers.ToList());
}
public ActionResult Create()
{
var states = _context.States.ToList();
var viewModel = new CustomerFormViewModel
{
States = states
};
return View(viewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CustomerFormViewModel vm)
{
if (ModelState.IsValid)
{
var customer = new Customer();
{
customer.CustDisplayName = vm.CustDisplayName;
customer.CustFirstName = vm.CustFirstName;
customer.CustLastName = vm.CustLastName;
customer.CustCompanyName = vm.CustCompanyName;
customer.CustAddress = vm.CustAddress;
customer.CustPhoneNumber = vm.CustPhoneNumber;
customer.CustMobileNumber = vm.CustMobileNumber;
customer.CustEmailAddress = vm.CustEmailAddress;
customer.StId = vm.StId;
}
_context.Customers.Add(customer);
_context.SaveChanges();
return RedirectToAction("Index");
}
else
{
vm.States = _context.States.ToList();
return View(vm);
}
}
public ActionResult Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var customervm = new CustomerFormViewModel();
{
Customer customer = _context.Customers.SingleOrDefault(c => c.CustId == id);
if (customer == null)
{
return NotFound();
}
customervm.CustId = customer.CustId;
customervm.CustDisplayName = customer.CustDisplayName;
customervm.CustFirstName = customer.CustFirstName;
customervm.CustLastName = customer.CustLastName;
customervm.CustCompanyName = customer.CustCompanyName;
customervm.CustAddress = customer.CustAddress;
customervm.CustPhoneNumber = customer.CustPhoneNumber;
customervm.CustMobileNumber = customer.CustMobileNumber;
customervm.CustEmailAddress = customer.CustEmailAddress;
// Retrieve list of States
var states = _context.States.ToList();
customervm.States = states;
// Set the selected state
customervm.StId = customer.StId;
}
return View(customervm);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(CustomerFormViewModel vmEdit)
{
if (ModelState.IsValid)
{
Customer customer = _context.Customers.SingleOrDefault(c => c.CustId == vmEdit.CustId);
if (customer == null)
{
return NotFound();
}
customer.CustDisplayName = vmEdit.CustDisplayName;
customer.CustFirstName = vmEdit.CustFirstName;
customer.CustLastName = vmEdit.CustLastName;
customer.CustCompanyName = vmEdit.CustCompanyName;
customer.CustAddress = vmEdit.CustAddress;
customer.CustPhoneNumber = vmEdit.CustPhoneNumber;
customer.CustMobileNumber = vmEdit.CustMobileNumber;
customer.CustEmailAddress = vmEdit.CustEmailAddress;
customer.StId = vmEdit.StId;
_context.Entry(customer).State = EntityState.Modified;
_context.SaveChanges();
return RedirectToAction("Index");
}
return View(vmEdit);
}
}
Create View
<div class="form-group">
#Html.LabelFor(c => c.CustDisplayName)
#Html.TextBoxFor(c => c.CustDisplayName, new { #class = "form-control" })
#Html.ValidationMessageFor(c => c.CustDisplayName)
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustFirstName)
#Html.TextBoxFor(c => c.CustFirstName, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustLastName)
#Html.TextBoxFor(c => c.CustLastName, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustCompanyName)
#Html.TextBoxFor(c => c.CustCompanyName, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustAddress)
#Html.TextBoxFor(c => c.CustAddress, new { #class = "form-control" })
#Html.ValidationMessageFor(c => c.CustAddress)
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustPhoneNumber)
#Html.TextBoxFor(c => c.CustPhoneNumber, new { #class = "form-control" })
#Html.ValidationMessageFor(c => c.CustPhoneNumber)
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustMobileNumber)
#Html.TextBoxFor(c => c.CustMobileNumber, new { #class = "form-control" })
#Html.ValidationMessageFor(c => c.CustMobileNumber)
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustEmailAddress)
#Html.TextBoxFor(c => c.CustEmailAddress, new { #class = "form-control" })
#Html.ValidationMessageFor(c => c.CustEmailAddress)
</div>
<div class="form-group">
#Html.LabelFor(s => s.StId)
#Html.DropDownListFor(s => s.StId, new SelectList(Model.States, "StId", "StAbbr"), "", new { #class = "form-control" })
#Html.ValidationMessageFor(s => s.StId)
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
Make another ViewModel class called IndexViewModel and put this on it:
public class IndexViewModel
{
public List<Customer> Customers { get; set; }
public List<Device> Devices { get; set; }
}
Here is your controller Action. Return the new IndexViewModel instead:
// GET: /<controller>/
public IActionResult Index()
{
return View(_context.Customers.ToList());
}
to
// GET: /<controller>/
public IActionResult Index()
{
var model = new IndexViewModel();
model.Customers = _context.Customers.ToList();
model.Devices = _context.Devices.ToList();
return View(model);
}
In your view, simply iterate the Device list:
#{
for(int i = 0; i < Model.Devices.Count(); i++)
{
var checkboxAttributes = Model.Devices[i].isChecked == true ?
(object) new { #class = "checkbox", #checked = "checked" } :
(object) new { #class = "checkbox" };
#Html.CheckBoxFor(model => model.Devices[i].DevType, checkboxAttributes)
#Html.LabelFor(model => model.Devices[i].DevType, new { #class = "label" })
}
}
Update 1
I'm sorry about the previous one but this is the correct version: It uses bootstrap style for the checkbox:
#{
for (int i = 0; i < Model.Devices.Count(); i++)
{
<div class="checkbox">
<label>
#Html.HiddenFor(model => model.Devices[i].DevId)
#Html.CheckBoxFor(model => model.Devices[i].isChecked)
#Html.DisplayFor(model => model.Devices[i].DevType)
#Html.HiddenFor(model => model.Devices[i].DevType)
</label>
</div>
}
}
You can use something like this, so you can reuse it for different models.
CheckboxViewModel:
public class CheckboxViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public bool Checked { get; set; }
}
Extension method:
public static IEnumerable<CheckboxViewModel> CreateCheckboxList<T>(this List<T> entities, Func<T, object> value, Func<T, object> text, Func<T, bool> isChecked)
{
return entities.Select(x => new CheckboxViewModel
{
Id = (int)value(x),
Name = text(x).ToString(),
Checked = isChecked(x)
});
}
Using example:
result = devices.CreateCheckboxList(x => x.Id, x => x.Name, x => selectedDevices.Contains(x.Id)).ToList();
#for (var deviceIndex = 0; deviceIndex < Model.Devices.Count(); deviceIndex ++)
{
<div class="form-group">
<div class="checkbox checkbox-primary">
#Html.HiddenFor(model => model.Devices[deviceIndex ].Id)
#Html.CheckBoxFor(model => model.Devices[deviceIndex ].Checked)
#Html.LabelFor(model => model.Devices[deviceIndex ].Checked, Model.Devices[deviceIndex ].Name)
</div>
</div>
}
I'm getting a validation error message on my DropDownList within my Create Action if I click the submit button without selecting a value from the DropDownList.
The validation error that I'm getting is The value "" is invalid. I would like the validation error message to say State is required! instead.
I added the required validation attribute to the StId property on the ViewModel but that did not resolve the issue.
Customer Model
public class Customer
{
public int CustId { get; set; }
public string CustFirstName { get; set; }
public string CustLastName { get; set; }
public int StId { get; set; }
public State State { get; set; }
}
State Model
public class State
{
public int StId { get; set; }
public string StAbbr { get; set; }
public List<Customer> Customers { get; set; }
}
CustomerFormViewModel
public class CustomerFormViewModel
{
public int CustId { get; set; }
[Required(ErrorMessage = "First Name is required!")]
[Display(Name = "First Name")]
public string CustFirstName { get; set; }
[Required(ErrorMessage = "Last Name is required!")]
[Display(Name = "Last Name")]
public string CustLastName { get; set; }
[Required(ErrorMessage = "State is required!")]
[Display(Name = "State")]
public int StId { get; set; }
public IEnumerable<State> States { get; set; }
}
CustomerController
public class CustomerController : Controller
{
private OneClickAwayDbContext _context;
public CustomerController(OneClickAwayDbContext context)
{
_context = context;
}
public ActionResult Index()
{
return View(_context.Customers.ToList());
}
public ActionResult Create()
{
var states = _context.States.ToList();
var viewModel = new CustomerFormViewModel
{
States = states
};
return View(viewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CustomerFormViewModel vm)
{
if (ModelState.IsValid)
{
var customer = new Customer();
{
customer.CustFirstName = vm.CustFirstName;
customer.CustLastName = vm.CustLastName;
customer.StId = vm.StId;
}
_context.Customers.Add(customer);
_context.SaveChanges();
return RedirectToAction("Index");
}
else
{
var stateViewModel = new CustomerFormViewModel
{
States = _context.States.ToList()
};
return View("Create", stateViewModel);
}
}
}
Create.chtml
#using (Html.BeginForm("Create", "Customer"))
{
<div class="form-group">
#Html.LabelFor(c => c.CustFirstName)
#Html.TextBoxFor(c => c.CustFirstName, new { #class = "form-control" })
#Html.ValidationMessageFor(c => c.CustFirstName)
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustLastName)
#Html.TextBoxFor(c => c.CustLastName, new { #class = "form-control" })
#Html.ValidationMessageFor(c => c.CustLastName)
</div>
<div class="form-group">
#Html.LabelFor(s => s.StId)
#Html.DropDownListFor(s => s.StId, new SelectList(Model.States, "StId", "StAbbr"), "", new { #class="form-control"})
#Html.ValidationMessageFor(s => s.StId)
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
}
Please include jquery.validate.js and jquery.validate.unobtrusive.js in your cshtml file
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
add this line in web.config
<appSettings>
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
include following jquery file in your layout page.
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
Using this your submit button click event is not going to your [HttpPost] Action of your view if any validation are required.
I have these models and a view model. When form posting to create the entries, the selected value for WardID and DoctorID becomes zero in the controllers POST method.
View code
#model NewClient.HospitalMgt.ViewModel.PatientAdmissionViewModel
....
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<div class="editor-label">
#Html.LabelFor(model => model.Admission.WardID, "Ward")
</div>
<div class="editor-field">
#Html.DropDownList("WardID", String.Empty)
#Html.ValidationMessageFor(model => model.Admission.WardID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Admission.DoctorID, "Doctor")
</div>
<div class="editor-field">
#Html.DropDownList("DoctorID", String.Empty)
#Html.ValidationMessageFor(model => model.Admission.DoctorID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Patient.PatientName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Patient.PatientName)
#Html.ValidationMessageFor(model => model.Patient.PatientName)
</div>
.... //more controls for properties of Patient
<div class="editor-label">
#Html.LabelFor(model => model.Admission.AdmissionNumber)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Admission.AdmissionNumber)
#Html.ValidationMessageFor(model => model.Admission.AdmissionNumber)
</div>
.... //more controls for properties of Admission
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Controller code
public ActionResult Create()
{
ViewBag.WardID = new SelectList(db.Wards, "WardID", "WardNumber");
ViewBag.DoctorID = new SelectList(db.Doctors, "DoctorID", "DoctorName");
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(PatientAdmissionViewModel Id)
{
if (ModelState.IsValid)
{
var c = new Patient()
{
Address = Id.Patient.Address,
ContactNumber = Id.Patient.ContactNumber,
EmergencyContact = Id.Patient.EmergencyContact,
PatientName = Id.Patient.PatientName,
};
var a = new Admission()
{
AdmissionNumber = Id.Admission.AdmissionNumber,
AdmissionDate = Id.Admission.AdmissionDate,
**WardID = Id.Admission.WardID, //becomes zero
DoctorID = Id.Admission.DoctorID //becomes zero**
};
db.Patients.Add(c);
db.Admissions.Add(a);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.WardID = new SelectList(db.Wards, "WardID", "WardNumber", Id.Admission.WardID);
ViewBag.DoctorID = new SelectList(db.Doctors, "DoctorID", "DoctorName", Id.Admission.DoctorID);
return View(Id);
}
Models and View models
//[NotMapped]
public class PatientAdmissionViewModel
{
public Patient Patient { get; set; }
public Admission Admission { get; set; }
}
public class Patient
{
public int PatientID { get; set; }
[Required(ErrorMessage = "A Patient Name is required")]
public string PatientName { get; set; }
public string Address { get; set; }
[Required(ErrorMessage = "A Contact Number is required")]
public string ContactNumber { get; set; }
public string EmergencyContact { get; set; }
public virtual Ward Ward { get; set; }
}
public class Admission
{
public int AdmissionID { get; set; }
public string AdmissionNumber { get; set; }
public Nullable<int> PatientID { get; set; }
public int WardID { get; set; }
public int DoctorID { get; set; }
public System.DateTime AdmissionDate { get; set; }
public virtual Ward Ward { get; set; }
public virtual ICollection<PatientPayment> PatientPayments { get; set; }
}
You use of #Html.DropDownList("WardID", String.Empty) and #Html.DropDownList("DoctorID", String.Empty) are generating inputs with name="WardID" and name="DoctorID" respectively, but you model does not contain properties with those names (it does however contain a property named Admission which contains those properties).
You 'view model' is not really a view model (a view model should not contain properties which are data models when editing). Your view model should also contain properties for the SelectList's so that you can strongly bind to your model. Your view model needs to be
public class PatientAdmissionViewModel
{
[Display(Name = "Ward"]
[Required(ErrorMessage = "Please select a ward")]
public int? SelectedWard { get; set; }
[Display(Name = "Doctor"]
[Required(ErrorMessage = "Please select a doctor")]
public IEnumerable<SelectListItem> WardList { get; set; }
public int? SelectedDoctor { get; set; }
public IEnumerable<SelectListItem> DoctorList { get; set; }
public string PatientName { get; set; }
... // other properties of Patient that you need in the view
public string AdmissionNumber{ get; set; }
... // other properties of Admission that you need in the view
}
and in the GET method, initialize an instance of the view model, set its properties and return it to the view
public ActionResult Create()
{
var model = new PatientAdmissionViewModel()
{
WardList = new SelectList(db.Wards, "WardID", "WardNumber"),
DoctorList = new SelectList(db.Doctors, "DoctorID")
};
return View(model);
}
and in the view
#Html.DropDownListFor(m => m.SelectedWard, Model.WardList, "-Please select-")
....
#Html.DropDownListFor(m => m.SelectedDoctor, Model.DoctorList, "-Please select-")
and finally, in the POST method, you initialize new instances of your data models, set their properties based on the values in the view models and save the data models.
I also recommend you read the answers to What is ViewModel in MVC?.
instead of this
#Html.DropDownList("WardID", String.Empty)
#Html.DropDownList("DoctorID", String.Empty)
use this on view
#Html.DropDownListFor(model => model.Admission.WardID, (SelectList)ViewBag.WardID, "--Select One--")
#Html.DropDownListFor(model => model.Admission.DoctorID, (SelectList)ViewBag.DoctorID, "--Select One--")
use this on controller
WardID = Id.Admission.WardID,
DoctorID = Id.Admission.DoctorID
I am very new to MVC5 and JQuery and I trying to create a cascading drop down. When the user selects a Practice from the drop down I am trying to get the Opticians that work in that Practice to populate.
Optician Model:
public class Optician
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid OpticianId { get; set; }
[ForeignKey("User")]
public string UserId { get; set; }
public virtual ApplicationUser User { get; set; }
public IEnumerable<SelectListItem> UserList { get; set; }
[ForeignKey("Practice")]
public Guid PracticeId { get; set; }
public virtual Practice Practice { get; set; }
public IEnumerable<SelectListItem> PracticeList { get; set; }
public virtual ICollection<ApplicationUser> Users { get; set; }
public virtual ICollection<Practice> Practices { get; set; }
}
Practice Model:
public class Practice
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Display(Name = "Practice")]
public Guid PracticeId { get; set; }
[Display(Name = "Practice Name")]
public string PracticeName { get; set; }
public virtual ICollection<Optician> Opticians { get; set; }
public virtual ICollection<Booking> Bookings { get; set; }
}
Application User Model:
public class ApplicationUser : IdentityUser
{
[Display(Name = "Title")]
public string Title { get; set; }
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
public string LastName { get; set; }
}
Controller :
public ActionResult TestDropDown()
{
var PracticeListItems = (from d in db.Practices
select d.PracticeName).ToList();
SelectList Practice = new SelectList(PracticeListItems);
ViewData["Practice"] = Practice;
return View();
}
public JsonResult Opticians(Guid? Id)
{
var OpticianList = (from d in db.Opticans
where d.PracticeId == Id
select d.User.FirstName).ToList();
return Json(OpticianList);
}
The View:
<script src="~/Scripts/jquery-1.10.2.js"></script>
<script>
$(document).ready(function () {
$("#Optician").prop("disabled", true);
$("#Practice").change(function () {
if ($("#Practice").val() != "Select") {
var PracticeOptions = {};
PracticeOptions.url = "/Bookings1/Opticians";
PracticeOptions.type = "POST";
PracticeOptions.data = JSON.stringify({ Practice: $("#Practice").val() });
PracticeOptions.datatype = "json";
PracticeOptions.contentType = "application/json";
PracticeOptions.success = function (OpticianList) {
$("#Optician").empty();
for (var i = 0; i < OpticianList.length; i++) {
$("#Optician").append("<option>" + StatesList[i] + "</option>");
}
$("#Optician").prop("disabled", false);
};
PracticeOptions.error = function () { alert("Error in getting Practices"); };
$.ajax(PracticeOptions);
}
else {
$("#Optician").empty();
$("#Optician").prop("disabled", true);
}
});
});
#using (Html.BeginForm("TestDropDown", "Bookings1", FormMethod.Post))
{
#Html.AntiForgeryToken()
<h4>Select Practcie & Opticians</h4>
<hr />
#Html.ValidationSummary()
<div class="form-group">
#Html.Label("Select Practice :", new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.DropDownList("Practice", ViewData["Practices"] as SelectList, new { #class = "form-control" })
</div>
</div><br />
<div class="form-group">
#Html.Label("Select Optician :", new { #class = "col-md-2 control-label" })
<div class="col-md-10">
<select id="Optician"></select>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Submit" />
</div>
</div>
}
However, when I run the application the Practice Name populates but the Optician First Name does not. There are no errors and I am unsure of where I am going wrong. Any help would be greatly appreciated.
Seems like you have a few issues with your code.. Starting with your SelectList.
When you define your select list it helps if you tell it what your Value and Text properties are..
public ActionResult TestDropDown()
{
var practices = new SelectList(db.Practices, "PracticeId", "PracticeName");
ViewData["Practices"] = practices;
return View();
}
Then you should probably return more information in your Opticians json result
[HttpPost]
public JsonResult Opticians(Guid? Id)
{
var opticianList = db.Opticians.Where(a => a.PracticeId == Id).Select(a => a.User).ToList();
return Json(opticianList);
}
In your javascript once you get the names sorted out out you can reference the property FirstName of the result.
$(document).ready(function () {
$("#Optician").prop("disabled", true);
$("#Practice").change(function () {
$.ajax({
url = "#Url.Action("Opticians","Bookings1")",
type = "POST",
data = {Id : $(this).val() }
}).done(function(OpticianList){
$("#Optician").empty();
for (var i = 0; i < OpticianList.length; i++) {
$("#Optician").append("<option>" + OpticianList[i].FirstName + "</option>");
}
$("#Optician").prop("disabled", false);
});
});
});
I'm not sure why you were passing paramater Practice to an action that took a parameter Id but it should be fixed in the code above.