views:

657

answers:

4

The Add view and the Edit view are often incredibly similar that it is unwarranted to write 2 views. As the app evolves you would be making the same changes to both.

However, there are usually subtle differences. For instance, a field might be read-only once it's been added, and if that field is a DropDownList you no longer need that List in the ViewData.

So, should I create a view data class which contains all the information for both views, where, depending on the operation you're performing, certain properties will be null?
Should I include the operation in the view data as an enum?
Should I surround all the subtle differences with <% if( ViewData.Model.Op == Ops.Editing ) { %> ?

Or is there a better way?

+2  A: 

I don't like the Views to become too complex, and so far I have tended to have separate views for Edit and Add. I use a user control to store the common elements to avoid repetition. Both of the views will be centered around the same ViewData, and I have a marker on my data to say whether the object is new or an existing object.

This isn't any more elegant than what you have stipulated, so I wonder if any of the Django or Rails guys can provide any input.

I love asp.net mvc but it is still maturing, and still needs more sugar adding to take away some of the friction of creating websites.

Andrew Rimmer
+2  A: 

I personally just prefer to use the if/else right there in the view. It helps me see everything going on in view at once.

If you want to avoid the tag soup though, I would suggest creating a helper method.

<%= Helper.ProfessionField() %>

string ProfessionField()
{
    if(IsNewItem) { return /* some drop down code */ }
    else { return "<p>" + _profession+ "</p>"; }        
}
Jim
+4  A: 

It's pretty easy really. Let's assume you're editing a blog post.

Here's your 2 actions for new/edit:

public class BlogController : Controller
{
   public ActionResult New()
   {
      var post = new Post();
      return View("Edit", post);
   }

   public ActionResult Edit(int id)
   {
      var post = _repository.Get(id);
      return View(post);
   }

   ....

}

And here's the view:

<% using(Html.Form("save")) { %>
<%= Html.Hidden("Id") %>

<label for="Title">Title</label>
<%= Html.TextBox("Title") %>

<label for="Body">Body</label>
<%= Html.TextArea("Body") %>

<%= Html.Submit("Submit") %>
<% } %>

And here's the Save action that the view submits to:

public ActionResult Save(int id, string title, string body)
{
   var post = id == 0 ? new Post() : _repository.Get(id);
   post.Title = title;
   post.Body = body;

   _repository.Save(post);

   return RedirectToAction("list");
}
Ben Scheirman
Rather than repost exactly what you've done, I might suggest you edit your answer to include an example of toggling a field to be read-only on the edit screen, as the original question asked about it.
Chris
A: 

You can specify a CustomViewData class and pass the parameters here.


public class MyViewData {
    public bool IsReadOnly { get; set; }
    public ModelObject MyObject { get; set; }
}

And both views should implement this ViewData. As a result you can use provided IsReadOnly property to manage the UserControl result.

As the controller uses this, you can unit test it and your views doesn't have implementation, so you can respect the MVC principles.

labilbe