Reputation: 197
here is the class I am working on:
public class appointment
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int appointment_id { get; set; }
[DataType(DataType.MultilineText)]
public string appointment_description { get; set; }
public int student_id { get; set; }
public virtual student student { get; set; }
public int sched_id { get; set; }
public virtual sched schedule { get; set; }
}
As you can see, one of my foreign keys is the "schedule".
here is my schedule class
public class sched
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int sched_id { get; set; }
public string sched_day { get; set; }
public TimeSpan sched_stime { get; set; }
public TimeSpan sched_etime { get; set; }
public int faculty_id { get; set; }
public virtual faculty faculty { get; set; }
}
I generated this in MVC 5 CRUD in create, this is the code in my view:
<div class="col-md-10">
@Html.DropDownList("sched_id", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.sched_id, "", new { @class = "text-danger" })
</div>
Here is my controller:
public ActionResult Book()
{
return View();
}
[HttpPost]
public ActionResult Book(CS.Models.appointment appoint)
{
if(ModelState.IsValid)
{
db.appointments.Add(appoint);
db.SaveChanges();
}
return RedirectToAction("Booked", "Home");
}
but there was an error:
There is no ViewData item of type 'IEnumerable<SelectListItem>'
All I want to do is display the data of the sched class (from the database) which a foreign key from the class I am working on in a dropdownlist.
Is there a way I can do that? I am very new in MVC.
Upvotes: 2
Views: 2542
Reputation: 17196
There are several things wrong here:
First of all - @Html.DropDownList("sched_id", null,
this line of code. When you build your select list, if I understood correctly, of schedules then, instead of null, you have to provide the list of items you want to build your DropDownList
from. This is the IEnumerable<SelectListItem>
mentioned in the error which can not be null. Which leads us to the second issue.
You're using you business models directly in your view which is not kinda right. Because, in your particular case, you have to initialize your list so you must have the collection of ALL schedules to select from. Which is not the part of your business model. Instead of CS.Models.appointment
you have to use a view model which will contain all properties you have fill to post your appointment
and two additional members:
IEnumerable<SelectListItem> ScheduleSelectListItems { get; set; };
int SelectedScheduleId { get; set; }
Populate the list of SelectListItems
you will have in your get action. Something like this:
public class AppointmentViewModel
{
public int appointment_id { get; set; }
public string appointment_description { get; set; }
public StudentViewModel student { get; set; }
public IEnumerable<SelectListItem> ScheduleSelectListItems { get; set; };
public int SelectedScheduleId { get; set; }
}
public ActionResult Book()
{
var items = db.schedules.ToList().Select(sched => new SelectListItem { Text = string.Format("{0} - {1}", sched.sched_stime, sched.sched_etime), Value = sched.Id });
var model = new AppointmentViewModel { ScheduleSelectListItems = items };
return View(model);
}
And do not forget to update your view to use AppointmentViewModel
as @model
.
<div class="col-md-10">
@Html.DropDownList("SelectedScheduleId", Model.ScheduleSelectListItems, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.SelectedScheduleId, "", new { @class = "text-danger" })
</div>
Which leads us to the third issue. Since you're no using any view models - you don't have any mapping (copying all fields from view model to actual business model which will be saved to the database). To simplify the task and avoid using external tools like AutoMapper
for this purpose at the moment you can do the mapping manually. In some external class, for example, to make controller actions code as clean as possible.
public static class Extensions
{
public static appointment ToAppointment(this AppointmentViewModel appointmentViewModel)
{
var result = new appointment
{
appointment_id = appointmentViewModel.appointment_id;
// Copy all other properties here
...
};
return result;
}
}
[HttpPost]
public ActionResult Book(AppointmentViewModel appoint)
{
if(ModelState.IsValid)
{
// Map you view model to the model
var appointment = appoint.ToAppointment();
// Get you selected schedul from the database using either foreighn key either navigation property
var schedule = db.schedules.FirstOrDefault(sched => sched.Id == appoint.SelectedScheduleId);
appointment.schedule = schedule;
db.appointments.Add(appointment);
db.SaveChanges();
}
return RedirectToAction("Booked", "Home");
}
Upvotes: 1