vendredi 31 juillet 2015

MVC pass POSTed data to a View

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");
}

Aucun commentaire:

Enregistrer un commentaire