Reputation: 2767
I'm having some issues with my DropDownLists, because when I post the information and my Model is not valid it comes back "empty" to the page triggering an error exactly like this question.
I've used the solution proposed there and it fixed my problem. Anyway, I wanted to avoid querying the database every time my ModelState is not valid and I came with this approach. I would like to know if it is valid or if there are better ways to do it now, considering that instead of MVC2 (which was the MVC version from the question) I'm now using MVC 5, maybe they added something new to tackle this.
What I've done was to use the TempData to persist the information when my model is not valid.
public class ViewModel
{
[DisplayName("Project")]
public int ProjectID { get; set; }
public List<SelectListItem> Projects { get; set; }
//Other fields
}
Now my Create() Action (that populates Projects)
[HttpGet]
public ActionResult Create()
{
ViewModel vmodel = new ViewModel();
vmodel.Projects = db.GetProjects(User.Identity.Name).Select(x => new SelectListItem { Text = x.Description, Value = x.Id }).ToList();
TempData["Projects"] = vmodel.Projects;
return View(vmodel);
}
And my post would be like this:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ViewModel vmodel)
{
//Clear TempData (in theory will clear my tempdata when read, so if this controller redirects to another action my tempdata will be clear)
List<SelectListItem> projects = (TempData["Projects"] as List<SelectListItem>);
if (ModelState.IsValid)
{
//...
}
//If it got here it's going back to the screen.
//Repopulate the TempData (allowing it to exist one more trip)
TempData["Projects"] = projects;
vmodel.Projects = projects
return View(atendimento);
}
Is this approach a good one? Is there a better way to achieve that without querying the database every single time?
Thanks a lot!
Upvotes: 3
Views: 2910
Reputation: 9002
Personally, I wouldn't worry about querying the database each time for this kind of operation.
What if projects are added/deleted? This could be the reason the save failed (selected project deleted) and the user would never realise it.
I usually write a method to populate all of my view model's SelectListItem
s and then use this in my Get
and in my Post
if the validation fails.
Upvotes: 1
Reputation: 218832
You don't need to use TempData
at all as you have a property in your view model to hold the dropdown items.
public ActionResult Create()
{
ViewModel vmodel = new ViewModel();
vmodel.Projects = GetProjects();
return View(vmodel);
}
private List<SelectListItem> GetProjects()
{
return db.GetProjects(User.Identity.Name)
.Select(x => new SelectListItem { Text = x.Description,
Value = x.Id }).ToList();
}
And in the view
@Html.DropDownListFor(s=>s.ProjectID,Model.Projects)
And in your HttpPost action, If ModelState is not valid, Reload the Projects
collection again (because http is stateless)
if(ModelState.IsValid)
{
// to do :Save and redirect
}
model.Projects = GetProjects();
return View(model);
You may cache the Projects
so that you do not need to hit the database every time, if you are too much worried about performance.
Upvotes: 6