Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should RenderAction be used with forms?

Tags:

My setup:

  • Have a view for a route like: /Pages/Details/2
  • The page details view has <% Html.RenderAction("CreatePageComment", "Comments"); %> to render a comment form
  • Comment form posts to Comments/CreatePageComment
  • /Comments/CreatePageComment returns RedirectToAction when a comment is created successfully
  • This all works nicely

My question:

If there is a validation error, how should I return to /Pages/Detail/1 and show the error in the comment form?

  • If I use RedirectToAction, it seems validation is tricky; should I even be using the Post-Redirect-Get pattern for validation errors, instead of just returning?
  • If I return View() it kicks me back to showing the CreateComment.aspx view (with validation, but just a form on a white page), not the /Pages/Details/2 route that called the RenderAction.

If the PRG pattern should be used, then I think I just need to learn how to do validation while using PRG. If not — and to me this seems better handled by returning View() — then I don't know how to get the user returned to the initial view, showing the form errors, while using RenderAction.

This feels like the game where you tap your head and rub your belly at the same time. I wasn't good at that one either. I'm new at MVC, so that's likely the problem here.

like image 603
Roger Rogers Avatar asked Jan 10 '10 05:01

Roger Rogers


1 Answers

I believe the answer is to use TempData, for example:

In my view (/Steps/Details) I have:

<!-- List comments -->
<% Html.RenderAction("List", "Comments", new { id = Model.Step.Id }); %>

<!-- Create new comment -->
<% Html.RenderAction("Create", "Comments", new { id = Model.Step.Id }); %>

In my comments controller I have my POST method:

    // POST: /Comments/Create
    [HttpPost]
    public ActionResult Create([Bind(Exclude = "Id, Timestamp, ByUserId, ForUserId")]Comment commentToCreate)
    {
        if (ModelState.IsValid)
        {
            //Insert functionality here

            return RedirectToAction("Details", "Steps", new { id = commentToCreate.StepId });

        }

    //If validation error
        else
        {

            //Store modelstate from tempdata
            TempData.Add("ModelState", ModelState);

            //Redirect to action (this is hardcoded for now)
            return RedirectToAction("Details", "Steps", new { id = commentToCreate.StepId });
        }
    }

Also in the comments controller is my GET method:

    //
    // GET: /Comments/Create

    public ActionResult Create(int id)
    {

        if (TempData.ContainsKey("ModelState"))
        {
            ModelStateDictionary externalModelState = (ModelStateDictionary)TempData["ModelState"];
            foreach (KeyValuePair<string, ModelState> valuePair in externalModelState)
            {
                ModelState.Add(valuePair.Key, valuePair.Value);
            }
        }
        return View(new Comment { StepId = id });
    }

This works great for me, but I'd appreciate feedback on whether this is a good practice, etc.

Also, I noticed that MvcContrib has a ModelStateToTempData decoration that appears to do this, but in a cleaner way. I'm going to try that next.

like image 199
Roger Rogers Avatar answered Nov 22 '22 07:11

Roger Rogers