My Index View displays a table of members loaded from it's Index() action method. Each table row has a checkbox. Outside the table is a Remove button.
The Remove button (when clicked) sends a POST request containing the ViewModel data (i.e. rows IDs) to it's POST action method Index().
All pretty standard so far. Until the next part (which I'm not happy about)...
In the Index() post action method, I store the rows IDs to TempData and then RedirectToAction to the Remove() GET action method. I would like to commit the data to the database here, but I have to display a "Are you sure you want to delete these records" page. Hence the redirect.
In the Remove() GET action method, I fetch the row data from TempData, then display the rows (using their IDs I fetch data from the database). Clicking the Submit button sends a POST request and the Remove() POST action method deletes these rows.
Using the TempData between both these GET/POST request 'pairs' looks like a path, i.e. poor design to get it to work. Given the data is a collection, List<int>(), i.e. a complex type, I can't use RedirectToAction here.
Question: Is there a better way to pass the POSTed data (selected rows) to be displayed to a View?
There are a number of SO posts asking whether a RedirectToAction via POST is possible, and the answer seems to 'No'. Which is understandable.
An Option: If there's no other approach, then I might have to consider using a Bootstrap Modal with the selected row data displayed, and a Remove button which POSTs via Ajax. But the problem with this is trying to read a list of selected (checkbox checked) rows from a View via jQuery appears difficult (for me with some working jQuery knowledge). Then POSTing via Ajax.
Code snippets below, I've removed unrelated code so ignore any syntax/spelling mistakes.
Index View
@model MyProject.Models.Members.MembersViewModel
... more view code
<div class="row">
<div class="col-md-12">
@using (Html.BeginForm("Index", "Members", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
@Html.AntiForgeryToken()
... table with @EditorFor()
<div class="col-md-2">
<input type="submit" value="Remove" id="buttonRemove" class="btn btn-primary" />
</div>
}
</div>
</div>
Controller Index() action methods
public ActionResult Index()
{
MembersViewModel membersViewModel = new MembersViewModel();
// Fetch members from the database
List<Member> members = _BLL.GetAllMembers();
// Map domain model to viewmodel
... automapper code here
membersViewModel.Members = members;
return View(membersViewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(MembersViewModel membersViewModel)
{
// Get the ids of the items selected (GetSelectedIDs() method on VM iterates through private list and returns selected IDs)
IEnumerable<int> selectedMembersIDs = membersViewModel.GetSelectedIDs();
// Store IDs
TempData["SelectedMembers"] = selectedMembersIDs.ToList();
return RedirectToAction("Remove");
}
Controller Remove() action methods
public ActionResult Remove()
{
List<int> selectedMembersIDs = TempData["SelectedMembers"] as List<int>;
if (selectedMembersIDs.Count == 0)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
// Fetch members details
List<Member> members = _BLL.GetSelectedMembers(selectedMembersIDs);
if (members.Count == 0)
{
return HttpNotFound();
}
// Map domain model to viewmodel
DeleteMembersViewModel deleteMembersViewModel = new DeleteMembersViewModel();
foreach (Member member in members)
{
deleteMembersViewModel.Members.Add(member);
}
return View(deleteMembersViewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Remove(DeleteMembersViewModel deleteMembersViewModel)
{
List<int> selectedMembersIDs = new List<int>();
foreach(Member member in deleteMembersViewModel.Members)
{
selectedMembersIDs.Add(member.ID);
}
_BLL.RemoveGroupMembers(selectedMembersIDs);
return RedirectToAction("Index");
}