Valid Comments

By
Dave
Project
Published
26 Jun 2010 23:02
Last Modified
8 Dec 2012 16:44

One of the trickier things I had to do for my blog engine was to support comment submission. Comments are only shown for a post when viewing the "Detail" view of a single blog post, and I wanted to show a form to submit a new comment at the bottom of this page.

In order to do this I had to use a specific ViewModel class to pass both the blog post, and a skeleton comment to the view. In this way, when the form is posted to the server, the default ModelBinder will present the controller with the comment. However, since the blog post is not on the HTML form (it only has the comment), I have to maintain a reference to the blog post using an HTML hidden form field:

<%= Html.HiddenFor(model => model.Comment.Post.Id) %>

The normal controller pattern to use when validating and saving data is as follows:

public ActionResult MyAction(...)
{
    ...
    Post post = myServiceLayer.GetPost(...);
    return View(post);
}

[HttpPost]
public ActionResult MyAction(...)
{
    ...
    if (myServiceLayer.AddComment(comment));
    {
        return RedirectToAction("MyAction");
    }
    else
    {
        // rebuild ViewModel and return view
        return View("MyView", new MyViewModel { Post = myServiceLayer.GetPost(...), Comment = comment });
    }
}

This pattern is used such that a successful post returns a client-side redirect to a page which re-displays the view. If the user refreshes their browser page, since we've done a re-direct there will be no prompts to re-submit the HTML form. This is called Post-Redirect-Get (PRG).

What happens if the comment fails validation? In this case, I need to re-display the form with the relevant errors and submitted values. I also need to ensure that the view is scrolled to the correct location so that the Comment form is displayed. Firstly I rebuild the ViewModel using the the submitted comment and blog post id from the hidden HTML field. Next, in order to return the ViewModel and ModelState, which contains the validation errors, I need to return a view. The only way I can find to specify a HTML anchor tag for this view is to include a HTML Action property on the HTML form in the view itself:

<div id="MyAnchor">
    MyTitle</div>
<%= Html.ValidationSummary(true, "...") %>
<% using(Html.BeginForm("MyAction", "MyController", FormMethod.Post,
    new { Action = string.Format("{0}#MyAnchor", Request.Url.AbsoluteUri) })) %>

A screenshot is shown below in Figure 1.

Blog comment validation

Figure 1. Blog comment validation.

I could have used AJAX to do this and avoid the problem of having to scroll the form, however I would still have to provide downlevel support for browsers with Javascript disabled.

Add Comment

*
*
*
Captcha
*
*Required