I’m trying to add a form to allow users to comment on posts on my blogging application. So far, I’ve added a form to the post details view and I can submit comments, adding them to my database correctly. However, I have a problem with displaying validation errors to the user. The comment form is contained within a partial view and is rendered using Html.RenderAction inside the post details view. I’d like to stress that I don’t want to use AJAX for this as I’d like to approach this from a progressive enhancement point-of-view.
Here’s the relevant posting action:
[HttpPost, Authorize]
public ActionResult AddComment(CommentViewModel newComment)
{
if (ModelState.IsValid)
{
Comment comment = new Comment(_userRepository.GetByUsername(User.Identity.Name));
Mapper.Map(newComment, comment);
_commentRepository.Add(comment);
_postsRepository.CommentAdded(comment.Article);
return RedirectToAction("Index", new { id = newComment.PostID });
}
// What do I do here?
}
I’ve tried several ways of returning views here but my issue is further complicated by some controller parameter validation that I have going on in the parent action:
//
// GET: /Posts/5/this-is-a-slug
public ActionResult Index(int id, string slug)
{
PostViewModel viewModel = new PostViewModel();
var model = _postsRepository.GetByID(id);
if (model != null)
{
if (slug == null || slug.CompareTo(model.Slug) != 0)
{
return RedirectToActionPermanent("Index", new { id, slug = model.Slug });
}
else
{
_postsRepository.PostVisited(model);
Mapper.Map(model, viewModel);
viewModel.AuthorName = _userRepository.GetById(model.AuthorID);
}
}
return View(viewModel);
}
This action basically mimics how SO’s URLs work. If a post ID is supplied, the post is fetched from the database along with a slug which is created when the post is created. If the slug in the URL doesn’t match the one in the database, it redirects to include the slug. This is working nicely but it does mean I’m having issues trying to populate my parent viewmodel, which is the following:
public class PostViewModel
{
public int PostID { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public string Slug { get; set; }
public DateTime DatePublished { get; set; }
public int NumberOfComments { get; set; }
public int AuthorID { get; set; }
public string AuthorName { get; set; }
public List<CommentViewModel> Comments { get; set; }
public CommentViewModel NewComment { get; set; }
}
What I was hoping would work is to populate PostViewModel.NewComment, test to see if it has data and then using it to display any model errors. Unfortunately, I’m lost as to how to accomplish that. This question helped me shape my approach, but it didn’t quite answer my problem.
Could someone give me a gentle push in the right direction? If my approach seems unreasonable, I’d love to find out why and what a potential fix would be.
Many thanks in advance.
Forgot to fill in my answer here. For anyone that happens to stumble on this, the answer was to use
TempDatato store theModelStateerrors and then repopulatingModelStatein the relevant controller action.Firstly, I declared a key in the controller which would be used to reference the data inside
TempData. I decided to base this on theCommentViewModeltype as both actions depend on it.In this first action, the code checks to see if
TempDatacontains data assigned to the key. If it does, it’s copied intoModelState.This action determines if the
ModelStateis valid before adding a comment to the database. If theModelStateis not valid, it is copied toTempData, which makes it available to the first action.