ASP.NET MVC cascading dropdown - c#

I have three tables in my database as follows:
University
id Name
1 A
2 B
Faculty
id id_uni name
1 1 AA
2 1 AA
cafedry
id id_uni id_faculty name
1 1 1 cc
I would like to create a cascading dropdown which will allow me to first select a University then a Faculty followed by a Cafedry. Below code is what i have tried so far.
public ActionResult Create()
{
ViewBag.fak_kod = new SelectList(db.Fakulteler, "id", "adi");
ViewBag.unikod = new SelectList(db.Universitetler, "id", "adi");
return View();
}
// POST: kafedras/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 = "id,unikod,fak_kod,adi")] kafedra kafedra)
{
if (ModelState.IsValid)
{
db.kafedra.Add(kafedra);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.fak_kod = new SelectList(db.Fakulteler , "id", "adi", kafedra.fak_kod);
ViewBag.unikod = new SelectList(db.Universitetler, "id", "adi", kafedra.unikod);
return View(kafedra);
}
and this cshtml
<div class="form-horizontal">
<h4>kafedra</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.unikod, "unikod", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("unikod", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.unikod, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.fak_kod, "fak_kod", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("fak_kod", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.fak_kod, "", new { #class = "text-danger" })
</div>
</div>
How can update this code to create a cascading dropdown with the three tables?

To start with, create a view model which has properties to render the options and store the selected item value.
public class CreateVm
{
[Required]
public int SelectedUniversity { set;get;}
[Required]
public int SelectedFaculty { set;get;}
public List<SelectListItem> Universities { set;get;}
public List<SelectListItem> Faculties { set;get;}
public CreateVm()
{
this.Faculties = new List<SelectListItem>();
this.Universities = new List<SelectListItem>();
}
}
Now in your GET action, create an object of this, load the Universities property and send the object to the view
public AcitonResult Create()
{
var vm=new CreateVm();
vm.Universities= GetUniversities();
return View(vm);
}
private List<SelectListItem> GetUniversities()
{
return db.Universitetler
.Select(x=>new SelectListItem { Value = x.Id,
Text = x.Name)
.ToList();
}
Now in your View, which is strongly typed to our CreateVm view model. we will use the DropDownListFor helper method to render the drop-downs
#model CreateVm
#using (Html.BeginForm("Create", "Home"))
{
#Html.DropDownListFor(a=>a.SelectedUniversity,Model.Universities,"Select one")
#Html.DropDownListFor(a => a.SelectedFaculty , Model.Faculties, "Select one",
new { data_url = Url.Action("GetFaculties") })
<input type="Submit" />
}
This will render 2 dropdowns, one with University options and the second one will be empty (because we did not load anything to the Faculties property). Now we will have some javascript(we are using jquery here for easy DOM manipulation) which will listen to the change event of the first drop-down(Universities) ,read the selected value and make an ajax call to the GetFaculties method and passing the selected university option value.
You can see that , i set a html5 data attribute for the second dropdown where i am storing the relative url to the GetFaculties method. So in my javascript, i can simply read this data attribute value and make a call to that url to get the data.
$(function () {
$("#SelectedUniversity").change(function () {
var v = $(this).val();
var url = $("#SelectedFaculty").data("url") + '?u=' + v;
var $fac= $("#SelectedFaculty");
$.getJSON(url, function (data) {
$fac.empty();
$.each(data, function (i, item) {
$fac.append($("<option>").text(item.Text).val(item.Value));
});
});
});
});
Now, let's add a GetFaculties action method which accepts the university id and return the faculties for that university in a list of SelectListItem as JSON array.
public ActionResult GetFaculties(int u)
{
var facultyList = db.Fakulteler
.Where(a=>a.id_uni==u)
.Select(x=>new SelectListItem { Value=x.Id,
Text=x.Name).ToList();
return Json(facultyList , JsonRequestBehavior.AllowGet);
}
You may use the same view model in the HttpPost action
[HttpPost]
public ActionResult Create(CreateVm vm)
{
if (ModelState.IsValid)
{
//read from vm and save
var k=new kafedra {
UniveristyId=vm.SelectedUniversity,
FacultyId=vm.SelectedFaculty,
};
db.kafedra.Add(k);
db.SaveChanges();
return RedirectToAction("Index");
}
vm.Universities= GetUniversities();
return View(vm);
}

Related

Create DropDownList of my model Jobs and use it in CreateEmployeesViewModel

First of all, excuse me if my English isn't that good.
I'm kind of stuck with this. I want to create a list of jobs and be able to choose which position the employee is in through a dropdown list.
This would be the model I have of the jobs. This is the model that created the connection to the database I'm using.
public partial class jobs
{
public jobs()
{
this.employees= new HashSet<employees>();
}
public int id_job { get; set; }
public string job{ get; set; }//NameJob
public virtual ICollection<employees> employees{ get; set; }
}
But as for the employee model I created a view model as follows.
public class CreateEmployeesViewModel
{
[Required (ErrorMessage = "It is necessary to enter a name")]
[Display(Name = "Name")]
public string Name{ get; set; } //Name
[Required (ErrorMessage = "It is necessary to enter the Last Name ")]
[Display(Name = "LastName")]
public string LName{ get; set; } //LastName
[Required (ErrorMessage = "What's your employee's job title?")]
public int Job{ get; set; } //idjob
}
In my controller, I have the following
//Get Add
public ActionResult Add()
{
return View();
}
And for the post
[HttpPost]
public ActionResult Add(CreateEmployeesViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
using (var db = new DBExerciseEntities())
{
var emp = new employees();//New Employee
emp.id_status = 1;//By default I set the new user as Active
emp.name= model.Name;//Get Name
emp.lname= model.LName;//get Last Name
/*This is what I want to turn into DropDownList. Instead of typing the job "int" I want
*to get the list of registered jobs*/
emp.id_job = model.Job;//get id_job
db.employees.Add(emp);
db.SaveChanges();
}
return Redirect(Url.Content("~/CEmployees/"));
}
The view is as the following
#model Exercise.Models.ViewModels.CreateEmployeesViewModel
#{
ViewBag.Title = "AddUser";
}
<h2>#ViewBag.Title</h2>
<div class="row">
<div class="col-md-12">
#using (Html.BeginForm("Add", "CEmployees", FormMethod.Post, new { }))
{
#Html.AntiForgeryToken()
#Html.ValidationMessage("Error", new { #class = "text-danger", #type = "text" })
#Html.LabelFor(d => d.Name)
#Html.TextBoxFor(d => d.Name, new { #class = "form-control" })
#Html.ValidationMessage("Name", new { #class = "text-danger" })
<br />
#Html.LabelFor(d => d.LName)
#Html.TextBoxFor(d => d.LName, new { #class = "form-control" })
#Html.ValidationMessage("LName", new { #class = "text-danger" })
<br />
<!-- I get the name of the [display] assigned in the model-->
#Html.LabelFor(d => d.Job)
#Html.TextBoxFor(d => d.Job, new { #class = "form-control" })<!--How can I do DropDownList?-->
<!-- mensajes de error -->
#Html.ValidationMessage("Job", new { #class = "text-danger" })
<br />
<div style="text-align:right;">
<input type="submit" class="btn btn-success" value="AddUser" />
</div>
}
</div>
</div>
If you could help me it would be very helpful as those I have seen do so with static lists or are simply confusing.
I just want to mention that I'm relying on a different code to get what I have so far and I'm new to MVC.
It's quite simple. Here is my solution. Hope to help, my friend :))
First, you need to add 1 list jobs in Add controller.
public ActionResult Add()
{
List<SelectListItem> lstJobs = new List<SelectListItem>
{
new SelectListItem { Text = "Select", Value = "0" },
new SelectListItem { Text = "Teacher", Value = "1" },
new SelectListItem { Text = "Engineer", Value = "2" },
new SelectListItem { Text = "Accountant", Value = "3" }
};
ViewData["job"] = lstJobs;
return View();
}
Then, show list job in View.
#using (Html.BeginForm("Add", "Employees", FormMethod.Post, new { }))
{
#Html.AntiForgeryToken()
#Html.ValidationMessage("Error", new { #class = "text-danger", #type = "text" })
#Html.LabelFor(d => d.Name)
#Html.TextBoxFor(d => d.Name, new { #class = "form-control" })
#Html.ValidationMessage("Name", new { #class = "text-danger" })
<br />
#Html.LabelFor(d => d.LName)
#Html.TextBoxFor(d => d.LName, new { #class = "form-control" })
#Html.ValidationMessage("LName", new { #class = "text-danger" })
<br />
<!-- I get the name of the [display] assigned in the model-->
#Html.LabelFor(d => d.Job)
#Html.DropDownList("Job", ViewData["job"] as List<SelectListItem>, new { #class = "form-control" })
#*#Html.TextBoxFor(d => d.Job, new { #class = "form-control" })*#
<!-- mensajes de error -->
#Html.ValidationMessage("Job", new { #class = "text-danger" })
<br />
<div style="text-align:right;">
<input type="submit" class="btn btn-success" value="AddUser" />
</div>
}
</div>
Finally, when you submit the form you will get Job value.
Please, don't use ViewData if you don't have to. Since a view model is in used, we just need to have another property in that view model to contain a list of available job titles.
The View Model
First, I would rename the model to just CreateEmployeeViewModel instead of CreateEmployeesViewModel since you're creating just single employee at a time. And then I would rename some of the properties and remove some unnecessary data annotations:
public class CreateEmployeeViewModel
{
[Required(ErrorMessage = "It is necessary to enter a name")]
public string Name{ get; set; } //Name
[Required(ErrorMessage = "It is necessary to enter the Last Name ")]
[Display(Name = "LastName")]
public string LName{ get; set; } //LastName
[Required(ErrorMessage = "What's your employee's job title?")]
public int SelectedJobId { get; set; } //idjob
public IDictionary<int, string> AvailableJobs { get; set; }
}
Here I used IDictionary to contain the list of available job titles since you have only the id and name. If you have more than 2 properties you want to pass, you can create your own view model class for each available job option and use IEnumerable or ICollection instead.
Initialize View Model in Controller
Next, on the HttpGet Add action method, you need to fetch the list of available job titles from your database and load it up to the view model, and return it to the view:
public ActionResult Add()
{
var vm = new CreateEmployeeViewModel
{
AvailableJobs = new Dictionary<int, string>();
};
using (var db = new DBExerciseEntities())
{
vm.AvailableJobs = db.jobs
.ToDictionary(x => x.id_job, x => x.job);
}
return View(vm);
}
The View
On the view you can use #Html.DropdownListFor() helper to generate the dropdown input for the SelectedJobId.
I've also changed your #Html.ValidationMessage to #Html.ValidationMessageFor().
By the way, I saw you used Bootstrap css classes. Come on! You can craft a better UI with that:
#model Exercise.Models.ViewModels.CreateEmployeeViewModel
#{
ViewBag.Title = "AddUser";
}
<h2>#ViewBag.Title</h2>
#using (Html.BeginForm("Add", "CEmployees", new { area = "" }, FormMethod.Post, new { }))
{
#Html.AntiForgeryToken()
#Html.ValidationMessage("Error", new { #class = "text-danger", #type = "text" })
<div class="form-group">
#Html.LabelFor(d => d.Name)
#Html.TextBoxFor(d => d.Name, new { #class = "form-control" })
#Html.ValidationMessageFor(d => d.Name, new { #class = "text-danger" })
</div>
<div class="form-group">
#Html.LabelFor(d => d.LName)
#Html.TextBoxFor(d => d.LName, new { #class = "form-control" })
#Html.ValidationMessageFor(d => d.LName, new { #class = "text-danger" })
</div>
<div class="form-group">
#Html.LabelFor(d => d.SelectedJobId)
#Html.DropdownListFor(d => d.SelectedJobId,
new SelectList(Model.AvailableJobs, "Key", "Value"),
new { #class = "form-control" }
)
#Html.ValidationMessageFor(d => d.SelectedJobId, new { #class = "text-danger" })
</div>
<div class="text-right">
<button type="submit" class="btn btn-success">Add User</button>
</div>
}
The SelectedJobId should contain user's selection when the form posts back to the server.

populating dropdown menu from database in ASP.NET MVC [duplicate]

This question already has answers here:
Populating a razor dropdownlist from a List<object> in MVC
(9 answers)
Closed 3 years ago.
I have a view to create an 'Appointment' after choosing some options in 3 different drop-down menus (Patient, Doctor, Clinic)
I need help with creating and populating these 3 drop-down menus.
I'm pretty new to ASP.NET MVC and C#. So, your help is most appreciated.
I'll include the appointment controller and appointment creation view code.
AppointmentController
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ClinicManagement.Models;
namespace ClinicManagement.Controllers
{
public class AppointmentController : Controller
{
// GET: Appointment
public ActionResult Index()
{
using (HospitalDatabaseEntities DataBase = new HospitalDatabaseEntities())
{
return View(DataBase.Appointments.ToList());
}
}
// GET: Appointment/Details/5
public ActionResult Details(int id)
{
using (HospitalDatabaseEntities DataBase = new HospitalDatabaseEntities())
{
return View(DataBase.Appointments.Where(x => x.AppintID == id).FirstOrDefault());
}
}
// GET: Appointment/Create
public ActionResult Create()
{
return View();
}
// POST: Appointment/Create
[HttpPost]
public ActionResult Create(Appointment appointment)
{
try
{
using (HospitalDatabaseEntities DataBase = new HospitalDatabaseEntities())
{
DataBase.Appointments.Add(appointment);
DataBase.SaveChanges();
}
// TODO: Add insert logic here
return RedirectToAction("Index");
}
catch
{
return View();
}
}
// GET: Appointment/Edit/5
public ActionResult Edit(int id)
{
using (HospitalDatabaseEntities DataBase = new HospitalDatabaseEntities())
{
return View(DataBase.Appointments.Where(x => x.AppintID == id).FirstOrDefault());
}
}
// POST: Appointment/Edit/5
[HttpPost]
public ActionResult Edit(int id, Appointment appointment)
{
try
{
using (HospitalDatabaseEntities DataBase = new HospitalDatabaseEntities())
{
DataBase.Entry(appointment).State = EntityState.Modified;
DataBase.SaveChanges();
}
// TODO: Add update logic here
return RedirectToAction("Index");
}
catch
{
return View();
}
}
// GET: Appointment/Delete/5
public ActionResult Delete(int id)
{
using (HospitalDatabaseEntities DataBase = new HospitalDatabaseEntities())
{
return View(DataBase.Appointments.Where(x => x.AppintID == id).FirstOrDefault());
}
}
// POST: Appointment/Delete/5
[HttpPost]
public ActionResult Delete(int id, FormCollection collection)
{
try
{
// TODO: Add delete logic here
using (HospitalDatabaseEntities DataBase = new HospitalDatabaseEntities())
{
Appointment appointment = (DataBase.Appointments.Where(x => x.AppintID == id).FirstOrDefault());
DataBase.Appointments.Remove(appointment);
DataBase.SaveChanges();
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
}
}
Appointment 'Create' View
#model ClinicManagement.Models.Appointment
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Appointment</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.DoctorID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.DoctorID, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.DoctorID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.PatientID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PatientID, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.PatientID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ClinicID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ClinicID, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ClinicID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Date, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Date, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Date, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create Appointment" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
If the drop down menu options are in a database, why not add a list to your model, populate that list in your GET ActionMethod and then render it using the DropdownListFor helper tag.
For example...
public class Appointment
{
public IEnumerable<SelectListItem> Clinic {get; set;}
//You should add this for every dropdown menu you intend to put in the list.
//I am guessing you already have a model like this as this was not in the question
}
public class Clinic
{
public int ClinicId {get; set;}
public string ClinicName {get; set;}
}
In the controller, you can then query the database for the options
public ActionResult Create()
{
var Clinic = context.Clinic.ToList();
var model = new Appointments()
{
Clinic = Clinic.Select(x => new SelectListItem
{
Value = x.ClinicId.ToString(),
Text = x.ClinicName
}
}
return View(model);
}
Like before, you would have to do this for all the fields. If you are worried about the numerous roundtrip to the database to get the values, do some research about Z.EntityFrameWork nuget pakages that lets you run batch SQL statements so you can get all three results with one database round trip.
Then in the view, you can do this...
#Html.DropDownListFor(m => m.ClinicId, Model.Clinic, "Select Clinic", new { #class = "form-control", id = "clinic" })
In Create controller GET , you should create 3 viewbag like
ViewBag.Patient = Database.Patient.ToList();
...
and in view, use dropdownlist:
#Html.DropDownList("PatientId", new SelectList(ViewBag.Accounts, "PatientId", "PatientName")), "choose the patient", new { #class = "form-control" }))

DropDownList selection is posting as null ASP.NET MVC

I have a DropDownList that is populated from a database table that has one column called "IncidentNumber". When using this DropDownList to post as part of a form into a different database table the application is throwing an exception because the DropDownList selection is posting as null. Any help here would be much appreciated!
Controller Action
var items = db.ViewIncidentNumbers.ToList();
if (items != null)
{
ViewBag.data = items;
}
if (ModelState.IsValid)
{
using (LogInformationEntities4 dc = new LogInformationEntities4())
{
dc.LandLostPersonDetails.Add(land);
dc.SaveChanges();
}
}
Code that is in the View
<div class="form-group">
#Html.LabelFor(model => model.Incident_Number, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("IncidentNumber", new SelectList(ViewBag.data, "IncidentNumber", "IncidentNumber"))
</div>
</div>
EDIT:
Incident Number class:
public partial class IncidentNumber
{
public int Id { get; set; }
public string IncidentNumber1 { get; set; }
}
My controller currently looks like:
[HttpGet]
public ActionResult NewLandMissingPerson()
{
string teamsession = string.Empty;
string username = string.Empty;
teamsession = Convert.ToString(Session["Callsign"]);
username = Convert.ToString(Session["Username"]);
LogInformationEntities4 dc = new LogInformationEntities4();
var items = dc.IncidentNumbers.ToList();
ViewBag.data = new SelectList(items.Select(x => new { Text = x.IncidentNumber1, Id = x.Id, Value = x.IncidentNumber1 }).ToList());
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult NewLandMissingPerson(LandLostPersonDetail land)
{
LogInformationEntities4 db = new LogInformationEntities4();
bool Status = false;
string response = "";
var items = db.IncidentNumbers.ToList();
ViewBag.data = new SelectList(items.Select(x => new { Text=x.IncidentNumber1, Id=x.Id, Value = x.IncidentNumber1 }).ToList());
if (ModelState.IsValid)
{
using (LogInformationEntities4 dc = new LogInformationEntities4())
{
dc.LandLostPersonDetails.Add(land);
dc.SaveChanges();
response = "New Missing Person Log Added.";
Status = true;
}
}
And the view currently looks like:
#Html.DropDownListFor(model => model.Incident_Number, new SelectList(ViewBag.data, "IncidentNumber1", "IncidentNumber1"))
I am currently getting an exception which says that IncidentNumber1 does not exist in System.Web.Mvc.SelectListItem
Okay, based from the comments, I think this will help.
Since, IncidentNumber is a property of LandLostPersonDetail class, then you should use DropDownListFor instead of DropDownList. DropDownListFor allows for client-side validation based on your model.. so if in your LandLostPersonDetail class.. let's say that IncidentNumber is required.. then if there is no value for that when the form is submitted then validation will occur on the client-side rather than having to wait and go to if (ModelState.IsValid) on the server-side.
Here is what I recommend changing:
In your HttpGet Action
ViewBag.IncidentNumberSelection = new SelectList(db.IncidentNumbers.ToList(), "IncidentNumber1", "IncidentNumber1");
In your View
<div class="form-group">
#Html.LabelFor(model => model.Incident_Number, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.Incident_Number,(IEnumerable<SelectListItem>)ViewBag.IncidentNumberSelection, "-- Select Incident Number --", new { #class = "form-control" })
</div>
</div>
Then, in your HttpPost actionresult.. you will no longer need:
var items = db.IncidentNumbers.ToList();
ViewBag.data = new SelectList(items.Select(x => new { Text=x.IncidentNumber1, Id=x.Id, Value = x.IncidentNumber1 }).ToList());
Please let me know if this helps.
#Html.DropDownListFor(m => m.IncidentNumber, new SelectList(ViewBag.data, "IncidentNumber", "IncidentNumber"))
In Controller you have to access with IncidentNumber property

MVC Razor DropDownListFor value not set in model

I'm trying to make a razor view that can post a model to my controller.
I've added a dropdown, however platform is always null when i post to my controller.
What am i doing wrong?
This is my view
#using (Html.BeginForm("Register", "Home", FormMethod.Post, new { #class = "form-horizontal", #id = "form" }))
{
#{
var platformList = new List<SelectListItem>() {
new SelectListItem(){ Value="I", Text="iOS"},
new SelectListItem(){ Value="A", Text="Android"},
};
}
<div class="form-group">
#Html.LabelFor(model => model.platform, "Plattform", new { #for = "inputPlatform", #class = "col-lg-3 control-label" })
<div class="col-lg-9">
#Html.DropDownListFor(model => model.platform, platformList, new { #class = "form-control", #id = "inputPlatform" })
</div>
</div>
}
This is my model
public class RegistrationModel
{
public String platform { get; set; }
}
My Controller
[HttpPost]
[AllowAnonymous]
public ActionResult Register(RegistrationModel RegistrationModelViewModel)
{
}
I couldn't get your view to work. There appears to be a formatting issue with the drop down declaration. It has an extra comma and was missing a end }. I kept getting a parse error, which is odd as you say you can get the post to work.
Anyway, I've created an example below which works and so I hope is of some use.
Model
public class RegistrationModel
{
public string platform { get; set; }
}
View
#model TestMVC.Models.RegistrationModel
#using (Html.BeginForm("Register", "Register", FormMethod.Post, new { #class = "form-horizontal", #id = "form" }))
{
var platformList = new List<SelectListItem>() {new SelectListItem(){ Value="I", Text="iOS"}, new SelectListItem(){ Value="A", Text="Android"}};
<div class="form-group">
#Html.LabelFor(model => model.platform, "Plattform", new {#for = "inputPlatform", #class = "col-lg-3 control-label"})
<div class="col-lg-9">
#Html.DropDownListFor(model => model.platform, platformList, new {#class = "form-control", #id = "inputPlatform"})
</div>
</div>
<button type="submit"> Submit</button>
}
Controller
public class RegisterController : Controller
{
[HttpGet]
public ActionResult Register()
{
return View();
}
[HttpPost]
public ActionResult Register(RegistrationModel model)
{
//Do something here;
}
}

Why i failed to get DropDownList value on submit event

In my MVC4 project I failed to get my DropDownList data on edit controller.
My UI syntax is bellow:
<div class="form-group">
#Html.HiddenFor(model => model.School.SchoolID)
#Html.LabelFor(model => model.School.SchoolName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.School.SchoolName)
#Html.ValidationMessageFor(model => model.School.SchoolName)
</div>
</div>
<div class="form-group">
#Html.HiddenFor(model => model.StudentCLass.ID)
#Html.LabelFor(model => model.StudentCLass.ClassName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.StudentCLass.ID, #ViewBag.StudentCLassList as SelectList,"Select Class")
#Html.ValidationMessageFor(model => model.StudentCLass.ID)
</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>
To fill the DropDownList I use bellow syntax:
public ActionResult Edit(int Id)
{
using (DB = new StudentContext())
{
var result = DB.Students.FirstOrDefault(c => c.ID == Id);
ViewBag.StudentCLassList = new SelectList(DB.StudentClasses
.Select(sc => new ViewModelClass
{
ID = sc.ID,
ClassName = sc.ClassName
}).ToList(), "ID", "ClassName");
return View(StudentInfo(result));
}
}
After click the submit button I can not get DropDownList value on my controller action.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(ViewModel.ViewModelStudents student)
{
var tempResult = student.StudentCLass.ID;
//return RedirectToAction("Index");
// return View(student);
}
Model structure
public partial class StudentClass
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public StudentClass()
{
Students = new HashSet<Student>();
}
public int ID { get; set; }
[StringLength(100)]
public string ClassName { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Student> Students { get; set; }
}
MVC Doen't post the DropDown list back to the Controller, You will have to populate dropdown list again in POST method:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(ViewModel.ViewModelStudents student)
{
var tempResult = student.StudentCLass.ID;
ViewBag.StudentCLassList = new SelectList(DB.StudentClasses
.Select(sc => new ViewModelClass
{
ID = sc.ID,
ClassName = sc.ClassName
}).ToList(), "ID", "ClassName");
return RedirectToAction("Index");
}
You could write the Dropdown list code in a function, if you don't want to read this dropdown list from DB evertime you can save it to Session[]:
public void PopulateDropDownList(){
var items = Session["MyDropDown"] != null ? (SelectList)Session["MyDropDown"] : null;
if(items ! null) {ViewBag.StudentCLassList; return;}
items = new SelectList(DB.StudentClasses
.Select(sc => new ViewModelClass
{
ID = sc.ID,
ClassName = sc.ClassName
}).ToList(), "ID", "ClassName");
Session["MyDropDown"] = ViewBag.StudentCLassList = items;
}
Note: If you save the DropDown list in Session, you don't have write it to ViewBag, but you can access it directly in View.
And call this method in Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(ViewModel.ViewModelStudents student)
{
var tempResult = student.StudentCLass.ID;
PopulateDropDownList();
return RedirectToAction("Index");
}
EDIT
I don't understand you are saying that you want the DropDown to be selected but you are Redirecting to `Index'.
If you do:
return View(student);
Instead of
return RedirectToAction("Index");
return RedirectToAction("Index"); will redirect you to Index page, refreshing your webpage.
EDIT 2:
I just noticed you have
#Html.HiddenFor(model => model.StudentCLass.ID)
MVC is posting the Value from this Hidden Back to the Controller. Try removing this,
The thing is that you have two controls with the same id
#Html.DropDownListFor(model => model.StudentCLass.ID
AND
#Html.HiddenFor(model => model.StudentCLass.ID)
I think you want something like this:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(ViewModel.ViewModelStudents student)
{
if (ModelState.IsValid)
{
// save changes and redirect
return RedirectToAction("Index");
}
else
{
using (DB = new StudentContext())
{
ViewBag.StudentCLassList = new SelectList(DB.StudentClasses.ToList(), "ID", "ClassName");
}
return View(student);
}
}
The framework will take care of preserving selected values across requests.

Categories

Resources