I am building MVC 4 application with C# and i have been doing a lot of add and edit views which are quite similar to each other. My question is how to reuse the same view with the model for the object returned by filling the form for add and edit of the items. Here is and example which i do in my application :
@model namespace.Register
@{
ViewBag.Title = "Manage User";
}
<div class="col1 manage-user">
<div>
@using (Html.BeginForm())
{
<h1>Add User</h1>
<div id="error" class="clear">@Html.ValidationSummary(true)</div>
<ul class="clear">
<li><label for="UserName">Username:</label>
@Html.EditorFor(x => x.UserName)
</li>
<li><label for="Password">Password:</label>
@Html.EditorFor(x => x.Password)
</li>
<li><label for="ConfirmPassword">Confirm password:</label>
@Html.EditorFor(x => x.ConfirmPassword)
</li>
<li>
<label for="level">Level:</label>
@Html.DropDownList("levels", Model.Elements.Levels)
</li>
</ul>
<div class="buttons">
<input type="submit" class="button create" value="Save" name="Save"/>
<input type="submit" class="button back" value="Back" name="Back" formnovalidate/>
</div>
}
</div>
and my Add Method :
public ActionResult AddUser()
{
Levels levels = new Levels(MyRepository.GetLevelsForUser(User.Identity.Name));
Register model = new Register(levels);
return View(register);
}
[HttpPost]
public ActionResult AddUser(Register model, FormCollection form)
{
if(form["Back"] != null)
{
return RedirectToAction("UserList");
}
if (ModelState.IsValid)
{
... add user logic
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "Please enter valid username and password.");
return View(model);
}
When i edit i need to open the same view as AddUser but filled with the proper properties in the model and post to save the changes in the model. Currently i use ViewData["Username"] , ||-|| "Password", and so to do this is there a better way to reuse this AddUser view ?
The register model is as the following
public class Register
{
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
public Levels Levels { get; set; }
public Register()
{
UserName = null;
Password = null;
ConfirmPassword = null;
Levels = null;
}
public Register(Levels levels)
{
UserName = null;
Password = null;
ConfirmPassword = null;
Levels = levels;
}
}
I usually leverage the
EditorTemplate
functionality for this purpose, decoupling the common parts in a dedicated Partial View.Follows an example based on your code (notice the
BeginForm
tags which differ in each one, while the form "meat" is digged up from the partial):Note: this is just a sample, it probably can be stripped out more but it's more of a proof of concept.
Add view cshtml
Edit view cshtml
Both views above would leverage this file (the name is not made up, it's dictated by MVC naming convention).
\Views\Shared\EditorTemplates\Register.cshtml
This also works for displaying data, the exact same principle applies but the partial goes in
\Views\Shared\DisplayTemplates
and is used throughDisplayFor()
.You can give the Templates any name you want, but if it doesn't match the type you'll have to use the overloads of
EditorFor
/DisplayFor
which take the view name as parameter.