Same view for both create and edit in MVC4

A View can definitely be shared for create and edit operations, using the same model. However, i would strongly recommend to think about it twice. In many cases, you will want to have a different view for edit operations(eg. hide some inputs that should not be editible) as well as the model could be slightly different, altought it might share some (or most) values. These difference will lead to some conditions in the view, checking whether you are creating or editing - which could make the code chaotic. Conclusion: before deciding whether to have a shared view, try to think of how much is the edit screen gonna differ from create screen, then you may decide.


I don't recommend it.

This should be a rather long answer, because there's a lot of things involved in the process, request and workflow of a normal MVC GET/POST workflow. I will try to answer your question with the minimum information required and why I do not recommend the use of the same view.

First, why?

  1. You don't have control over the views, which may have over-posting;
  2. No flexibility;
  3. Not reusable views or parts;
  4. Hard to maintain the views (one change in the view must be tested on both actions).

My suggested approach would be to have different actions/views but share common code:

Create both views as normal.

You will have duplicated code, but not all code is the same, for example, you may not want to send an ID on the create action, this is not directly related to your question, but using the same view implies you are also sending the same data, and this is not recommended, especially for over-posting or mass assignment. More info about mass assignment here (an Architectural Approach is what I'm using here).

So let's start from what are you going to receive in your controllers. In this case I used inheritance but it's not the only strategy.

Binding models

public class UpdateBindingModel : CreateBindingModel {
    // since we are not using the same binding model, 
    // we can have a "real" validation rules on our update binding and view.
    [Required]
    public int? Id {get;set;}
}

public class CreateBindingModel {
    // no id here prevent overposting.
    [Required]
    public string Name {get;set;}
    [Required]
    public int? CountryId {get;set;}
}

That will make sure the data you send to your Create and Edit is the minimum needed and nothing else.

Let's then see the View Models that will be sent to the View, for this example I will include a List that will be used to select some value but should not be posted (the list) to the controller, only the selected value.

View models

public class CreateViewModel : CreateBindingModel {
    public IEnumerable<SelectListItem> CountryList {get;set;}
}

public class UpdateViewModel : UpdateBindingModel {
    public IEnumerable<SelectListItem> CountryList {get;set;}
}

As you can see, this gives you lot of flexibility but still have some duplicated code (the extra information needed on view model for both views) which can be mitigated in several ways (depending the needs/context):

  1. Have an action to retrieve the common data and using @Html.Action("GetCountryList");
  2. Use the same View Model aka CreateUpdateViewModel and discarding extra UpdateBindingModel properties in the view but still posting the corresponding model on POST.
  3. Having your binding models as properties and select one or the other in the specific view. (better use @Html.EditorFor instead of partials so Model Binder will work with no additional change on code)

The controller actions will look like:

Controller

[HttpGet]
public ActionResult Create(){
    ViewData.Model = new CreateViewModel();
    return View();
}

[HttpPost]
public RedirectToRouteResult Create(CreateBindingModel binding) {
    // check valid model state and create data
    return RedirectToAction("Index");
}

[HttpGet]
public ActionResult Update(int id) {
    var objectToEdit = service.GetObjectToEdit(id);
    ViewData.Model = new UpdateViewModel(objectToEdit);
    return View();
}

[HttpPost]
public RedirectToRouteResult Update(UpdateBindingModel binding) {
    // check valid model state and update data
    return RedirectToAction("Index");
}

And your views:

Views

Update.cshtml
<form action="Update">
    @Html.HiddenFor(Model.Id);
    @Html.Partial("EditFieldsPartial")
    <button>delete</button> // no delete button on create.
    <button>create new</button> // you can have a create new instead of update.
</form>

Create.cshtml
<form action="Create">
    @Html.Partial("EditFieldsPartial")
</form>

Note: code is incomplete and didn't use helpers in most cases for brevity and clarity. Do NOT copy paste :D


Sure you can.

On post, check in your controller whether the primary key has value 0 then Insert, otherwise Update.

View should be the same for Create and Edit.

Just remember to include:

@Html.HiddenFor(model=>model.ID)

In your view

For example:

Model:

public class DescriptionModel
{
    [Key]
    public int ID { get; set; }

    public string Description { get; set; }
}

CreateEdit.cshtml:

@model DescriptionModel

@using (Html.BeginForm("CreateEdit"))
{
    @Html.HiddenFor(model=> model.ID)
    @Html.EditorFor(model=> model.Description)
    <input type="submit" value='Submit' />
}

DescriptionModel controller:

public ActionResult Create()
{
    return View("CreateEdit", new DescriptionModel());
}
public ActionResult Edit(int id)
{
    return View("CreateEdit", db.DescriptionModels.Find(id));
}

// Submit and add or update database
[HttpPost]
public ActionResult CreateEdit(DescriptionModel model)
{
    if (ModelState.IsValid)
    {
       // No id so we add it to database
       if (model.ID <= 0)
       {
           db.DescriptionModels.Add(model);
       }
       // Has Id, therefore it's in database so we update
       else
       {
           db.Entry(model).State = EntityState.Modified;
       }
       db.SaveChanges();
       return RedirectToAction("Index");
    }

    return View(model);
}