Can we have a single razor view for both Create and Edit operations?
If yes, how do we achieve this?
The [Bind] attribute will let you specify the exact properties of a model should include or exclude in binding. In the following example, the Edit() action method will only bind StudentId and StudentName properties of the Student model class.
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?
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):
@Html.Action("GetCountryList");
CreateUpdateViewModel
and discarding extra UpdateBindingModel
properties in the view but still posting the corresponding model on POST.@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); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With