Customizing Auto Generated Edit View

Customizing Auto-Generated Edit View in ASP.NET MVC Application

In this article, I am going to discuss customizing the auto-generated edit view in ASP.NET MVC application. This is a continuation part of our previous article, so please read our previous article before proceeding to this article. In our previous article, we discussed customizing the auto-generated Index and Create views.

Customizing Auto-Generated Edit View

Run the application and navigate to the Index view. Click on the Edit button which will take you to edit view to edit an employee which should display as shown below.

Customizing Auto Generated Edit View in ASP.NET MVC Application

In the edit view if you want “Select Department” as the first item in the “Department” dropdown list 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 the “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” })

Creating a Field as Non Editable:

Let’s make employee name as 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
Prevent Updating using Bind Attribute:

Now let’s discuss using the 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 the “Edit” action method of Employee Controller 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);
}

Here, 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 the “Save” button on “Edit” view we get a validation error stating – The Name field is required. This is because the “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.

Adding Model Error Dynamically:

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 the Name value. To fix this error on 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 am going to discuss HTML helpers in ASP.NET MVC application. Here, 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 needs. 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 *