Reputation: 79
I apologise in advance for asking a question that has been answered before but i am still a novice and find it difficult to apply solutions to my own problem.
I have a view model that i populate some data on creating and then intend to fill with data using a cascading drop down list (i cant use any client side scripts)
public class StudentPortalModel
{
public SelectList LocationListModel { get; set; }
public SelectList ResidenceListModel { get; set; }
public int ChosenLocation { get; set; }
public int ChosenBlock { get; set; }
public int ChosenFlat { get; set; }
public int ChosenRoom { get; set; }
public int ChosenResidence { get; set; }
}
I have an action in a controller which populates the viewmodel with some lists that i use for drip down menus as so:
[HttpGet]
public ActionResult SelectResidence()
{
List<Location> objLocationList = (from data in db.Locations select data).ToList();
SelectList objLocationModelData = new SelectList(objLocationList, "LocationId", "LocationName", 0);
List<Residence> objResidenceList = (from data in db.Residences select data).ToList();
SelectList objResidenceModelData = new SelectList(objResidenceList, "ResidenceId", "BlockNumber", 0);
StudentPortalModel objStudentPortalModel = new StudentPortalModel();
objStudentPortalModel.LocationListModel = objLocationModelData;
objStudentPortalModel.ResidenceListModel = objResidenceModelData;
return View(objStudentPortalModel);
}
I want the model data sent to the view to be returned back to the controller
@using (Html.BeginForm("SelectLocation", "StudentPortal", FormMethod.Post))
{
@Html.DropDownListFor(x => x.ChosenLocation, Model.LocationListModel, "---Select Location---")
<input type="submit" value="Submit"/>
}
i want all the data i post to the view to be retained when sent back to the HttpGet method.
[HttpPost]
public ActionResult SelectLocation(StudentPortalModel testPortalInstance)
{
List<Location> objLocationList = (from data in db.Locations select data).ToList();
SelectList objLocationModelData = new SelectList(objLocationList, "LocationId", "LocationName", 0);
List<Residence> objResidenceList = (from data in db.Residences select data).Where(i => i.LocationId == testPortalInstance.ChosenLocation).DistinctBy(x => x.BlockNumber).ToList();
SelectList objResidenceModelData = new SelectList(objResidenceList, "ResidenceId", "BlockNumber", 0);
testPortalInstance.LocationListModel = objLocationModelData;
testPortalInstance.ResidenceListModel = objResidenceModelData;
return View("SelectResidence", testPortalInstance);
}
As you all probably know, the only data that gets sent back is ChosenLocation as that is sent back when the end user picks it from the drop down list, everything else is empty
Essentially i need a way of retaining what options the user is choosing for each drop down list. This allows me to narrow down what room a user wishes to pick till i am able to decipher a single room from a table and assign it to a user.
My biggest problem is I cant seem to find the viewmodel data I send to the view and assign it to the same value to send back. when I post back to the controller everything is empty meaning I have to recreate data.
I apologise for my rambling, I put it down to the fact I have only been programming a month.
Thank you in advance for any help!
Upvotes: 2
Views: 2474
Reputation:
Not really clear why you would not want to use javascript/jquery (it would give much better performance) but you will need to pass the selected values to each GET method from the relevant POST method. Assuming the first step is to choose a location, then a residence, your controller methods would be
public ActionResult SelectResidence()
{
List<Location> locations = (from data in db.Locations select data).ToList();
StudentPortalModel model = new StudentPortalModel()
{
LocationListModel = new SelectList(locations, "LocationId", "LocationName")
}
return View(model);
}
Note there is no point generating a SelectList
for ResidenceListModel
since its not used in the first view which will be
@model StudentPortalModel
@using (Html.BeginForm()) // no need to add parameters
{
@Html.DropDownListFor(x => x.ChosenLocation, Model.LocationListModel, "---Select Location---")
<input type="submit" value="Submit"/>
}
which will post back to
[HttpPost]
public ActionResult SelectResidence(StudentPortalModel model)
{
if (!ModelState.IsValid)
{
// repopulate locations and return view
}
return RedirectToAction("SelectResidence", new { locationID = model.ChosenLocation });
}
which will redirect to
public ActionResult SelectResidence(int locationID)
{
List<Residence> residences = (from data in db.Residences select data).Where(i => i.LocationId == locationID).ToList();
StudentPortalModel model = new StudentPortalModel()
{
ChosenLocation = locationID,
ResidenceListModel = new SelectList(residences, "ResidenceId", "BlockNumber")
}
return View(model);
}
whose view will be
@model StudentPortalModel
@using (Html.BeginForm())
{
@Html.HiddenFor(x => x.ChosenLocation)
@Html.DropDownListFor(x => x.ChosenResidence, Model.ResidenceListModel , "---Select Residence---")
<input type="submit" value="Submit"/>
}
which will post back to
public ActionResult SelectResidence(StudentPortalModel model)
{
if (!ModelState.IsValid)
{
// repopulate residences based on the value of model.ChosenLocation and return view
}
// your model now contains values for both ChosenLocation and ChosenResidence
}
Similarly if you then need to go to a view to choose a room you would redirect to (say) public ActionResult SelectResidence(int locationID, int residenceID)
Upvotes: 2
Reputation: 5357
Partial views, should make use of
@Html.RenderChildAction
Which is a method on the Html Helper you use in your razor views.
Your controller methods should be decorated with [ChildActionOnly]
Which is an attribute that makes it so MVC routes the action in a way where it can only be called via RenderChildAction, which prevents people from going to it's url in their browser.
Secondly, you should be passing your models instance to the view on each step of the cascade.
return Partial(theModel);
or return Partial("somePartialView", theModel);
Those returns would be example returns from controller Actions that return an ActionResult type.
Finally, your form tags can pass your model to the postback. MVC will automatically JSON serialize it and JSON deserialize it for you, so no need to have tons of hidden tags (maybe in older versions of MVC, but I know this works in mvc 4+).
Here is an example partial view:
@model StudentPortalModel
@using (Html.BeginForm("SetSelection", "StudentPortal", new { model = Model}, FormMethod.Post, null))
{
//Do Form Stuff Here
}
Notice above I am passing the model as a route data object... MVC will serialize it to json, post it in the post data, then the controller will deserialize it automatically into the model parameter because it's an anonymous object who's model property and json type info matches the name of the "model" parameter on the controller action.
Example controller method
[HttpPost]
public ActionResult SetSelection(StudentPortalModel model)
{
return View("NextCascade", Model)
}
Now, I didn't use ChildAction only on the above, because you want to be able to post to this. [ChildActionOnly] is for the Action that loads your partial view, not for the action it is posting back to, those get [HttpPost].
The three attributes in total are:
[ChildActionOnly]
[HttpGet]
[HttpPost]
You can use both HttpGet and HttpPost on the same action, but that is the default. In other words if you leave off the attributes all together it will route for get and post requests. Put if you only put HttpGet it will not route for Post Requests (you can't post to it), etc.
Now, let's say that PartialView is called StudentSelection:
There should be a parent action on the controller that returns it initially on the get request (first load) decorated with [ChildActionOnly]. And you should use @Html.RenderChildAction to render that partial view on that action.
Upvotes: 1
Reputation: 21
Your Model in the post action should have fields that match the input name's in your form that the user fills out. That allows the default MVC model binding to set the user's chosen values to the fields in your StudentPortalModel.
Upvotes: 0