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
Related
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);
}
I want to edit this data in database and return new data
when i click on save button data doesn't change
Here is controller :
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(CustomPerformancePerformersModel customPerformancePerformersModel)
{
if (ModelState.IsValid)
{
int perfromanceId = Convert.ToInt32(TempData.Peek("CurrentPerformanceId"));
customPerformancePerformersModel.performanceObj = db.Performances.Where(x => x.PerformanceId == perfromanceId).FirstOrDefault();
db.Entry(customPerformancePerformersModel.performanceObj).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.EventId = new SelectList(db.Events, "EventId", "Name", customPerformancePerformersModel.performanceObj.EventId);
ViewBag.VenueId = new SelectList(db.Venues, "VenueId", "Name", customPerformancePerformersModel.performanceObj.VenueId);
ViewBag.Performers = new SelectList(db.PerformerPerformances, "Performers", "Name", customPerformancePerformersModel.performanceObj.PerformerPerformances);
return View(customPerformancePerformersModel.performanceObj);
}
and here is the html:
<div class="form-group">
#Html.LabelFor(model => model.performanceObj.IsVisible, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.performanceObj.IsVisible)
#Html.ValidationMessageFor(model => model.performanceObj.IsVisible, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.performanceObj.IsFeatured, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.performanceObj.IsFeatured)
#Html.ValidationMessageFor(model => model.performanceObj.IsFeatured, "", new { #class = "text-danger" })
</div>
</div>
Try the following:
if (ModelState.IsValid)
{
int perfromanceId = Convert.ToInt32(TempData.Peek("CurrentPerformanceId"));
// There is no need to use Where. FirstOrDefault has an overload using predicates.
var savedPerformance = db.Performances.FirstOrDefault(x => x.PerformanceId == perfromanceId);
// If the performance couldn't be found, then you could add the error to the model state and return it to the view.
if(savedPerformance == null)
return View(customPerformancePerformersModel.performanceObj);
// Update properties from performance in database with new performance.
savedPerformance.someProperty = customPerformancePerformersModel.performanceObj.someProperty;
db.Performances.Attach(savedPerformance);
db.Entry(savedPerformance ).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
Ideally your code will look something like the following:
public ActionResult Edit(int performanceId)
{
var model = db.Performances.FirstOrDefault(m => m.PerformanceId == performanceId);
return View(model);
}
[HttpPost] //[HttpPatch] is technically correct, but most people I see tend to use only GET and POST actions.
[ValidateAntiForgeryToken]
public ActionResult Edit(CustomPerformancePerformersModel model)
{
if (ModelState.IsValid)
{
db.Entry(model).State = EntityState.Modified;
db.SaveChanges();
}
}
You're retrieving the object from the database and tracking it in your GET action, modifying it using your form, then marking it as modified in your update action. This is strictly if you're using the MVC pattern, and will look different (see below) if you're using separate data and view models. You'll likely run into trouble with this approach if your view doesn't have fields (hidden or not) for all properties on your model.
Using separate data and view models, you'd have something like this:
public ActionResult Edit(int performanceId)
{
var performance = db.Performances.FirstOrDefault(m => m.PerformanceId == performanceId);
var model = new PerformanceViewModel(performance); //In this constructor, copy properties from your data model to your view model
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(PerformanceViewModel model)
{
var performance = db.Performances.FirstOrDefault(m => m.PerformanceId == model.PerformanceId);
model.Update(performance);
db.SaveChanges();
}
With a sample view model:
public class PerformanceViewModel
{
public PerformanceViewModel(CustomPerformanceePerformersModel model)
{
PerformanceId = model.performanceObj.PerformanceId;
IsVisible = model.performanceObj.IsVisible;
IsFeatured = model.performanceObj.IsFeatured;
}
public int PerformanceId { get; set; }
public bool IsVisible { get; set; }
public bool IsFeatured { get; set; }
public void Update(CustomPerformancePerformersModel model)
{
model.performanceObj.IsVisible = IsVisible;
model.performanceObj.IsFeatured = IsFeatured;
}
}
Here you're creating a separate object (view model) that holds only the necessary data for your view, then using the data from that object to update your data model. I prefer this because it takes the ability to effectively directly modify the database, and because you can do any necessary intermediate processing (casting strings to bools, et cetera) in the Update(Model) method.
This question already has answers here:
The ViewData item that has the key 'XXX' is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'
(6 answers)
Closed 6 years ago.
This is giving me a hard time to implement. I've generated a controller and view to handle updating a model.
However in the Create.cshtml I need to add a drop down with database users (using db.Users.Tolist()) to populate the dropdown.
<div class="form-group">
#Html.LabelFor(model => model.UserId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
// #Html.EditorFor(model => model.UserId, new { htmlAttributes = new { #class = "form-control" } })
#Html.DropDownListFor(model => model.UserId, ViewData["u"] as IEnumerable<SelectListItem>)
</div>
</div>
So I've taken #Html.EditorFor() and replaced it with #Html.DropDownListFor() to show the dropdown list. And this does work but I get an error when I click submit.
The ViewData item that has the key 'UserId' is of type 'System.String' but must be of type 'IEnumerable'.
Here's the Model.
public class pdf
{
[Key]
public int ID { get; set; }
public string UserId { get; set; }
public Guid FileGuid { get; set; }
public string FileName { get; set; }
public string FileLocation { get; set; }
}
And the Create controller.
public ActionResult Create()
{
if (ModelState.IsValid)
{
var u = db.Users.Select(x => new { UserId = x.Id, UserName = x.UserName }).ToList();
//u[0].UserName
ViewBag.userinfo = new System.Web.Mvc.MultiSelectList(u, "UserId", "UserName");
IEnumerable<SelectListItem> u1 = new SelectList(db.Users.ToList(), "Id", "UserName");
ViewData["u"] = u1;
}
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID,UserId,FileGuid,FileName,FileLocation")] pdf pdf)
{
if (ModelState.IsValid)
{
db.tblPDF.Add(pdf);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(pdf);
}
I feel that I'm almost there. But just need a push in the right direction to make this work.
This is how you can make your SelectListItems
ViewData["items"] = db.UserProfiles
.Select(x => new SelectListItem() { Text = x.UserName, Value = x.UserId.ToString() });
This is how you would use it
#Html.DropDownListFor(model => model.UserId, ViewData["items"] as IEnumerable<SelectListItem>)
I've never tried passing a selectlistitem collection directly to the page. I typically add the list to the model and then create a new selectlistitem collection with razor.
Do you have the choice to modify your model?
#Html.DropDownListFor(model => model.UserId, Model.availableUsers.Select(user => new SelectListItem() { Text = user.displayVariable, Value = user.userId, Selected = user.userId == model.UserId }).ToArray())
What I'm trying to do...
I am trying to get a newly added item to display in a cascading dropdownlist.
Overview...
The first dropdownlist (I'll call it ddlCategory) is for selecting a Category of electrical devices (ie. Appliances, Audio-Visual, Lighting, etc.). The second dropdownlist (I'll call ddlElecDev) is populated with the devices which are filtered by the selected Category. If the device isn't listed in ddlElecDev then the user can click a link to add a new one. After saving the newly added electrical device, the user is redirected back to the original page with the electrical device id as a parameter.
All the above seems to work fine. However, when the user is redirected to the first page, not only is the newly added electrical device not selected in ddlElecDev, but it doesn't even appear in the list. Strangely, if I refresh the page, it is automatically selected.
Can anyone explain to me how to get the newly added device to be selected without having to refresh the page?
Here's the markup for selecting the category and electrical device:
<div class="form-group">
#Html.LabelFor(model => model.SelectedCategory, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.SelectedCategory, Model.Categories, "Select a Category", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.SelectedCategory, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ElectricalDeviceID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.CascadingDropDownListFor(
expression: model => model.ElectricalDeviceID,
triggeredByProperty: model => model.SelectedCategory,
url: Url.Action("GetElectricalDevices", "ElectricalDeviceConfigurations"),
ajaxActionParamName: "categoryId",
optionLabel: "Select an Electrical Device",
disabledWhenParrentNotSelected: false,
htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.ElectricalDeviceID, "", new { #class = "text-danger" })
#Html.ActionLink("Not Listed? Add a new Electrical Device", "AddNew", "ElectricalDevices", new { returnUrl = string.Format("/ElectricalDeviceConfigurations/AddConfiguration?eventVendorId={0}", Model.EventVendorID) }, null)
</div>
</div>
The documentation for the Cascading DropDownList Helper can be found at
https://github.com/alexanderar/Mvc.CascadeDropDown
Here's the Controller method for selecting the Electrical Device:
public ActionResult AddConfiguration(int? eventVendorId, int? newElecDev)
{
(Some code removed for brevity)
var selectedCategoryId = db.ElectricalDeviceCategoryLookups.Where(cat => cat.Category == Enums.ElectricalDeviceCategory.All).FirstOrDefault().ID;
var electricalDeviceID = (newElecDev.HasValue) ? newElecDev : null;
return View(new ElecDevConfigSelectionViewModel { EventVendorID = eventVendorId, EventVendor = eventVendor, Categories = GetCategories(), SelectedCategory = selectedCategoryId, ElectricalDeviceID = electricalDeviceID });
}
Here's the controller methods for populating the Categories and the Electrical Devices:
private List<SelectListItem> GetCategories()
{
var categories = new List<SelectListItem>();
db.ElectricalDeviceCategoryLookups.OrderBy(c => c.Description).ToList().ForEach(item => categories.Add(new SelectListItem { Text = item.Description, Value = item.ID.ToString() } ));
return categories;
}
public ActionResult GetElectricalDevices(int? categoryId)
{
if (categoryId.HasValue)
{
var selCategory = db.ElectricalDeviceCategoryLookups.Where(cat => cat.ID == categoryId).FirstOrDefault().Category;
var elecDevicesSelectList = new List<SelectListItem>();
var elecDevices = (selCategory == Enums.ElectricalDeviceCategory.All) ? db.ElectricalDevices.OrderBy(ed => ed.Name).ToList() : db.ElectricalDevices.Where(ed => ed.Category == selCategory).OrderBy(ed => ed.Name).ToList();
elecDevices.ForEach(ed => elecDevicesSelectList.Add(new SelectListItem { Text = ed.Name, Value = ed.ID.ToString() }));
return Json(elecDevicesSelectList, JsonRequestBehavior.AllowGet);
}
return null;
}
Here's the View Model:
public class ElecDevConfigSelectionViewModel
{
public int? EventVendorID { get; set; }
public EventVendor EventVendor { get; set; }
[Display(Name = "Category")]
public int SelectedCategory { get; set; }
public IList<SelectListItem> Categories { get; set; }
[Display(Name = "Electrical Device")]
public int? ElectricalDeviceID { get; set; }
}
Here's the controller methods for adding a new electrical device:
// GET: ElectricalDevices/AddNew
public ActionResult AddNew(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
var selectedCategoryId = db.ElectricalDeviceCategoryLookups.FirstOrDefault().ID;
return View(new AddNewElectricalDeviceViewModel { ReturnUrl = returnUrl, Categories = GetCategories(), SelectedCategory = null });
}
// POST: ElectricalDevices/AddNew
// 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 AddNew(AddNewElectricalDeviceViewModel model)
{
if (ModelState.IsValid)
{
var selectedCategory = db.ElectricalDeviceCategoryLookups.Find(model.SelectedCategory);
var electricalDevice = new ElectricalDevice
{
Name = model.ElectricalDevice.Name,
Description = model.ElectricalDevice.Description,
Category = selectedCategory.Category,
Wattage = model.ElectricalDevice.Wattage
};
db.ElectricalDevices.Add(electricalDevice);
db.SaveChanges();
var returnUrl = string.Format("{0}&newElecDev={1}", model.ReturnUrl, electricalDevice.ID);
return RedirectToLocal(returnUrl);
}
return View();
}
Here's the View Model for adding a new electrical device:
public class AddNewElectricalDeviceViewModel
{
public string ReturnUrl { get; set; }
[Display(Name = "Category")]
public int? SelectedCategory { get; set; }
public IList<SelectListItem> Categories { get; set; }
public ElectricalDevice ElectricalDevice { get; set; }
}
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.