Customizing Auto Generated Edit View

Customizing Auto Generated Edit View

In this article, I will discuss customizing auto generated edit view in ASP.NET MVC application. Please read CRUD Operations using Entity Framework and Customizing Auto-generated Index and Create View articles before proceeding to this article as we are going to work with the same example that we started in CRUD Operations using Entity Framework article.

If we want “Select Department” as the first item in the “Department” dropdown list on “Edit” view then
REPLACE THE FOLLOWING LINE

@Html.DropDownList(“DepartmentId”,null , htmlAttributes: new { @class = “form-control” })

with

@Html.DropDownList(“DepartmentId”,null , “Select Department”, htmlAttributes: new { @class = “form-control” })

Notice that a textbox is used for gender. It is ideal to have a dropdown list for gender rather than a textbox. To achieve this, make the following changes to “Edit.cshtml” view.

REPLACE THE FOLLOWING CODE
@Html.EditorFor(model => model.Gender, new { htmlAttributes = new { @class = "form-control" } })
with	
@Html.DropDownList("Gender", new List<SelectListItem>
{
new SelectListItem { Text = "Male", Value="Male" },
new SelectListItem { Text = "Female", Value="Female" }
}, "Select Gender", new { @class = "form-control" }) 

Let’s make “Name” non-editable. To achieve this

Change the following code in Edit.cshtml view

@Html.EditorFor(model =>model.Name)

TO
@Html.DisplayFor(model =>model.Name)

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

After all the modification below is our code for Edit.cshtml view

@model CRUD_Using_EF.Models.Employee
@{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Employee</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(model => model.EmployeeId)
<div class="form-group">
@Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DisplayFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
@Html.HiddenFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Gender, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("Gender", new List<SelectListItem>
{
new SelectListItem { Text = "Male", Value="Male" },
new SelectListItem { Text = "Female", Value="Female" }
}, "Select Gender", new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.Gender, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.City, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.City, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.City, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Salary, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Salary, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Salary, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.DepartmentId, "DepartmentId", htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("DepartmentId", null, "Select Department", htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.DepartmentId, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>

At this point, we will still be able to change the “Name” property of the employee using tools like Fiddler. There are several ways to prevent “Name” property from being updated.

1. Use UpdateModel() function and pass include and exclude list as a parameter

2. Use Bind attribute

3. Use interfaces

Now let’s discuss using BIND attribute to prevent updating “Name” property using tools like Fiddler. Along the way, I will demonstrate adding model validation errors dynamically.

Change the implementation of “Edit” controller action method that responds to [HttpPost] request as shown below

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "EmployeeId,Gender,City,Salary,DepartmentId")] Employee employee)
{
Employee employeeFromDB = db.Employees.Single(emp => emp.EmployeeId == employee.EmployeeId);
employeeFromDB.Gender = employee.Gender;
employeeFromDB.City = employee.City;
employeeFromDB.Salary = employee.Salary;
employeeFromDB.DepartmentId = employee.DepartmentId;
if (ModelState.IsValid)
{
db.Entry(employeeFromDB).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.DepartmentId = new SelectList(db.Departments, "Id", "Name", employee.DepartmentId);
return View(employee);
}

Please note that we have not included “Name” property from model binding using “Bind” attribute. Even without BIND attribute users will not be able to change the “NAME” of the employee as we are copying only the required properties (Excluding NAME property) from “employee” object to “employeeFromDB” which in turn is persisted to the database. Since I want to demonstrate adding model validation errors dynamically let the attribute be there.

At this point if we run the application and click on “Save” button on “Edit” view we get a validation error stating – The Name field is required. This is because “Name” property is decorated with [Required] attribute in “PEmployee.cs” file. To prevent the validation error, remove the [Required] attribute. 

Now the PEmployee.cs file looks as follows
using System.ComponentModel.DataAnnotations;
namespace CRUD_Using_EF.Models
{
[MetadataType(typeof(EmployeeMetaData))]
public partial class Employee
{
}
public class EmployeeMetaData
{
public string Name { get; set; }
[Required]
public string Gender { get; set; }
[Required]
public string City { get; set; }
[Required]
public string Salary { get; set; }
[Required]
public int DepartmentId { get; set; }
}
}

Now run the application and see Edit view is working as expected.

The problem with this change is that the “Name” field on “Create” view is no longer mandatory. This means we will now be able to create a new employee without NAME. To fix the “Create” view let’s add model validation errors dynamically. Change the implementation of the “Create” action method that responds to [HttpPost] request as shown below.

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "EmployeeId,Name,Gender,City,Salary,DepartmentId")] Employee employee)
{
if (string.IsNullOrEmpty(employee.Name))
{
ModelState.AddModelError("Name", "The Name field is required.");
}
if (ModelState.IsValid)
{
db.Employees.Add(employee);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.DepartmentId = new SelectList(db.Departments, "Id", "Name", employee.DepartmentId);
return View(employee);
}

That’s it. Run the application and see Create View is also working as expected.

In the next article, I will HTML helpers in ASP.NET MVC application.

SUMMARY

In this article, I try to explain Customizing Auto Generated Edit View in ASP.NET MVC application as well as how to add dynamic model validation error. I hope this article will help you with your need. I would like to have your feedback. Please post your feedback, question, or comments about this article.

Leave a Reply

Your email address will not be published. Required fields are marked *