ViewModel gets null in action method

I am using ViewModel to retrieve the input data into a controller action. But the ViewModel gets empty values ​​in the properties. I create one partial view

and in this partial view I create drop-down lists binding the ViewModel and then I rendering that partial view in another View >

Below is my code

My ViewModel:

public class LookUpViewModel { RosterManagementEntities rosterManagementContext = new RosterManagementEntities(); public LookUpViewModel() { tblCurrentLocations = from o in rosterManagementContext.tblCurrentLocations select o; tblStreams = from o in rosterManagementContext.tblStreams select o; } [Required] public virtual IEnumerable<tblCurrentLocation> tblCurrentLocations { get; set; } [Required] public virtual IEnumerable<tblStream> tblStreams { get; set; } 

My partial view:

 @model PITCRoster.ViewModel.LookUpViewModel @Html.Label("Location") @Html.DropDownListFor(M=>M.tblCurrentLocations, new SelectList(Model.tblCurrentLocations, "LocationId", "Location"), "Select Location") @Html.ValidationMessageFor(M=>M.tblCurrentLocations) <br /> @Html.Label("Stream") @Html.DropDownListFor(M => M.tblStreams, new SelectList(Model.tblStreams, "StreamId", "Stream"), "Select Streams") @Html.ValidationMessageFor(M => M.tblStreams) 

My view in which I do this partial view

 @{ ViewBag.Title = "Resources"; } <script src="~/Scripts/jquery.validate.min.js"></script> <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script> <h2>Resources</h2> @using (Html.BeginForm("AddResource", "Resources", FormMethod.Post)) { @Html.AntiForgeryToken() @Html.ValidationSummary(true) Html.RenderPartial("_LookUpDropDowns", new PITCRoster.ViewModel.LookUpViewModel()); <br /> <input type="submit" value="Create" /> } 

And this is my controller action method: [HttpPost]

 public void AddResource(LookUpViewModel testName) { //code } 

When I put the debugger in my controller action control method, it goes to this Action method. But the ViewModel object has null in it. I tried to access the entered values ​​using FormCollection and I get all the data as expected ...

Below is my code for controller action with FormCollection

  [HttpPost] public void AddResource(FormCollection form) { var x = form["tblStreams"]; //I get value here.. } 

Can someone explain to me why I am not getting the value in the ViewModel? Thanks...

+5
source share
2 answers

You cannot bind a drop-down list to a set of complex objects - in your case IEnumerable<tblCurrentLocation> and IEnumerable<tblStream>

A <select> tag returns only one value (the value of the selected parameter), therefore, in the POST method, testName.tblCurrentLocations = "1" tries to do so testName.tblCurrentLocations = "1" (provided that the value of the selected parameter is 1 ), which, of course, fails, and property set to null

You need a view model that contains the properties you want to bind to (and ideally would include the SelectList used by the DropDownListFor() helper)

 public class LookUpViewModel { [Display(Name = "Location")] [Required(ErrorMessage = "Please select a location")] public int SelectedLocation { get; set; } [Display(Name = "Stream")] [Required(ErrorMessage = "Please select a stream")] public int SelectedStream { get; set; } public SelectList LocationList { get; set; } public SelectList StreamList { get; set; } } 

Then in view

 @Html.LabelFor(m => m.SelectedLocation) @Html.DropDownListFor(m => m.SelectedLocation, Model.LocationList, "-Please select-") @Html.ValidationMessageFor(m => m.SelectedLocation) @Html.LabelFor(m => m.SelectedStream) @Html.DropDownListFor(m => m.SelectedStream, Model.StreamList, "-Please select-") @Html.ValidationMessageFor(m => m.SelectedStream) 

and in the controller

 public ActionResult Edit() { LookUpViewModel model = new LookUpViewModel(); ConfigureViewModel(model); return View(model); } [HttpPost] public ActionResult Edit(LookUpViewModel model) { if (!ModelState.IsValid) { ConfigureViewModel(model); return View(model); } // model.SelectedLocation will contain the value of the selected location // save and redirect } private void ConfigureViewModel(LookUpViewModel model) { // populate your select lists var locations = from o in rosterManagementContext.tblCurrentLocations select o; model.LocationList = new SelectList(locations, "LocationId", "Location"); .... // ditto for streams } 

Note that, as stated in Maximilian's answer, your view model should only contain the properties necessary for the view. The controller is responsible for filling in the values. A view model should never access a database β€” it should not even know that it exists.

+4
source

This answer will not solve your problem directly, but first of all I recommend redirecting the ViewModel filling at least to the controller (since otherwise it will recreate the DBContext every time the constructor is called). ViewModel should contain only data - no logic. And I would use DBContext in Using

ViewModel:

 public class LookUpViewModel { [Required] public virtual IEnumerable<tblCurrentLocation> tblCurrentLocations { get; set; } [Required] public virtual IEnumerable<tblStream> tblStreams { get; set; } 

Controller:

 public ActionResult Foo() { LookUpViewModel ViewModel = new LookUpViewModel(); using(RosterManagementEntities rosterManagementContext = new RosterManagementEntities()) { ViewModel.tblCurrentLocations = from o in rosterManagementContext.tblCurrentLocations select o; ViewModel.tblStreams = from o in rosterManagementContext.tblStreams select o; } return View(ViewModel); } 
+2
source

All Articles