0

Lets's Say that i have a two model classes; Project, and Comment as following :

public class Project
{
    Public int ProjectID { get; set; }
    public string Title { get; set; }
    public virtual List<Comment> Comments { get; set; }
}

public class Comment
{
    Public int CommentID { get; set; }
    public string Text { get; set; }
}

I used the CRUD creation feature when i created the "controller and the views" for my Project class.

Now, in the 'Details' view for the Project, i want to add form to add comments to this project, i want the 'Details' view to be something like :

Project Name : -- Project Name Goes Here --

Comments : 1. ---------
           2. ---------
[Text Area To Enter Comment] and [SUBMIT] button

The submit button should add comment to the project's comments list.

How do I achieve this?

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
Khaled Obaid
  • 275
  • 3
  • 13
  • I tried to change the parameter for the @BeginForm(Method,CommentController,ProjectID) in the project's Details view. but when the execution reach the Method on the CommentController i have null in the argument. so i'm not sure if this is the right way to think for the solution. – Khaled Obaid May 21 '14 at 21:08

2 Answers2

1

I recommend creating a ViewModel that represents all the data you need for a view. These ViewModels are specific to MVC.

Model:

public class IndexViewModel
{
  public Project Project { get; set; }
  public IEnumerable<Comment> Comments { get; set; }
  public Comment NewComment { get; set; }
}

Controller Method:

public ActionResult Index()
{
  var model = new IndexViewModel();

  // populate data, including an empty NewComment
  model.NewComment = new Comment();
  model.NewComment.ProjectId = model.Project.ProjectId;

  return View(model);
}

View:

@model IndexViewModel

@using (Html.BeginForm("Comment", "Create"))
{
  @Html.EditorFor(m => m.NewComment.CommentText)

  @Html.HiddenFor(m => m.NewComment.ProjectId)
}

This means adding or removing data a view needs is pretty straight forward. The form should only need to be around NewComment. The post model would look like:

Model:

public class CreateCommentViewModel
{
  public Comment NewComment { get; set; }
}

Control Method:

public ActionResult Create(CreateCommentViewModel model)
{
  // logic for creating comment
}

DotNetFiddle Example. The only problem with Dot Net Fiddle is it only supports a single view (that I know of) so when you pass the Text of the new comment, I throw an exception with the text of the comment.

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
  • He needs the ProjectId in the CreateCommentViewModel, or It will be lost at limbo! – Fals May 21 '14 at 21:26
  • That's a good solution, but i want to know how to submit form from a Model specific view to another controller passing different model. – Khaled Obaid May 21 '14 at 21:27
  • `Comment` should already have a `ProjectId` field, it should be `Html.HiddenFor()` with the value from `Model.Project.ProjectId`. – Erik Philips May 21 '14 at 21:28
  • Model binder doesn't know ANYTHING about the original model passed to the view. All it knows about is the form values coming back. If they match, then the values are populated. In this case the models for `NewComment` match so the modelbinder populates the values. – Erik Philips May 21 '14 at 21:33
0

Erik Philips was close to answer, actually his solution works, but i found most accurate answer to my question using Html.Action.

// 1. Add this line to Project's Detail View.
@Html.Action("CreateComment","Comment", new { ProjectID = Model.ProjectID })

// 2. Add this method to the Comment Controller class, and send the id 
//    to the comment view.
public ActionResult CreateComment(int ProjectID)
{
    return View(new Comment() { ProjectID = ProjectID });
}

// 3. Create view for the CreateComment controller action
@using (Html.beginForm("SubmitComment","Comment"))
{
    @Html.HiddenFor(ProjectID=>Model.ProjectID) // This value you send it
    @Html.EditorFor(model=>Model.Text)
    <input type="submit" value="Add Comment" />
}

// 4. add method to the comment controller
//    since i alreay public ActionResult Details(int id) in the project controller 
//    to display the project's details and comments. i will call it after adding comment
public ActionResult SubmitComment(Comment comment)
{
    dbContext = new myDatabaseContext();
    dbContext.Comments.Add(comment);
    dbContext.SaveChanges();
    return RedirectToAction("Details","Project", new { id=comment.ProjectID })
}

Thanks for contributing in this post

Khaled Obaid
  • 275
  • 3
  • 13