January 2018 : Instructor-led Online Course in ASP.NET Core 2.0. Conducted by Bipin Joshi. Read more...
Registration for January 2018 batch of ASP.NET Core 2.0 instructor-led online course has already started. Conducted by Bipin Joshi. Register today ! Click here for more details.

Utilize HTML5 ContentEditable in ASP.NET MVC to Edit View Content

Usually ASP.NET MVC developers create two separate views for displaying data in read-only and editable form. Although this technique works well, you can utilize a feature of HTML5 to conveniently read as well as edit data on the same view. HTML5 offers contenteditable attribute that magically turns any read-only area of a web page into an editable region. Using contenteditable in combination with some jQuery code you can easily develop a view that toggles between read-only and editable mode.

Let's see how this can be accomplished with a simple example. Have a look at the following view:

As shown above , the Index view displays Employee details such as EmployeeID, FirstName, LastName and Notes. Notice that the Notes region, although appears to be editable, is not a textbox! It's actually a <div> element whose contenteditable attribute is set to true. The FirstName and LastName values are also wrapped in a <div> that is contenteditable. A <div> element marked with contenteditable enters edit mode when you click on it and becomes read-only when you click somewhere outside on the page.

The following screen shot shows the Notes <div> after edit operation is over:

Although HTML5 contenteditable attribute allows you easily toggle between read-only and edit mode, it doesn't automatically persist the changes to the storage. But a dash of jQuery code can do that for you. Let's see how.

The following code shows the Index() action method of Home controller:

public ActionResult Index()
{
    using (NorthwindEntities db = new NorthwindEntities())
    {
        return View(db.Employees.First());
    }
}

The Index() action simply picks the first Employee record from the Employees table of Northwind database and sends it to the Index view. For the sake of testing the above code simply sends the first Employee object to the view.

The Home controller also has an action method - Save() - that does the job of saving an Employee to the database. The Save() method is called through jQuery code and is shown below:

public JsonResult Save(Employee obj)
{
    using (NorthwindEntities db = new NorthwindEntities())
    {
        Employee existing = db.Employees.Find(obj.EmployeeID);
        existing.FirstName = obj.FirstName;
        existing.LastName = obj.LastName;
        existing.Notes = obj.Notes;
        db.SaveChanges();
        return Json("Employee modified successfully!");
    }
}

The Save() action receives an Employee object to be saved in the database and returns a success message as a JsonResult. Inside, the code simply finds an existing Employee, modifies the concerned properties and calls SaveChanges() to save the data. You need to update the Employee this way because the Employee object received in the Save() method doesn't have all the properties of the Employee model class.

Next, you need to create the Index view and add the following markup to it:

@model ContentEditableDemo.Models.Employee

<!DOCTYPE html>
<html>
...
<body>
    <h1>Employee Details</h1>
    <table border="1" cellpadding="10">
        <tr>
            <td>Employee ID :</td>
            <td><div id="employeeID">@Model.EmployeeID</div></td>
        </tr>
        <tr>
            <td nowrap>First Name :</td>
            <td>
                <div id="firstName" contenteditable="true">
                 @Model.FirstName
                </div>
             </td>
        </tr>
        <tr>
            <td>Last Name :</td>
            <td>
                <div id="lastName" contenteditable="true">
                 @Model.LastName
                </div>
            </td>
        </tr>
        <tr>
            <td>Notes :</td>
            <td>
                <div id="notes" contenteditable="true">
                 @Model.Notes
               </div>
             </td>
        </tr>
        <tr>
            <td colspan="2">
                <input id="save" type="button" value="Save" />
            </td>
        </tr>
    </table>
    <br />
    <span id="msg"></span>
</body>
</html>

Notice all the <div> elements marked in bold letters. They have contenteditable attribute set to true. Thus FirstName, LastName and Notes regions can be edited by clicking on the respective <div>. Clicking on the Save button triggers some jQuery code that sends the modified Employee to the Save() action wrote earlier. This jQuery code is shown below:

$(document).ready(function () {
    $("#save").prop("disabled", true);

    $("div").on('input', function () {
        $("#save").prop("disabled", false);
    });

    $("#save").click(function () {
        var modifiedEmployee = {};
        modifiedEmployee.EmployeeID = $("#employeeID").text();
        modifiedEmployee.FirstName = $("#firstName").text();
        modifiedEmployee.LastName = $("#lastName").text();
        modifiedEmployee.Notes = $("#notes").text();

        $.post("/home/save", modifiedEmployee, function (msg) {
            $("#save").prop("disabled", true);
            $("#msg").html("<strong>" + msg + "</strong>");
        });

    });
});

When the page loads in the browser, you set the disabled DOM property of the Save button to true. Since the Employee record is not yet edited the Save button is disabled. The code then wires event handler for the input event of all the <div> elements. This way you can trap when the content is modified (of course, this is not a sophisticated and precise arrangement but tha's ok for our example). In the input event handler you simple enable the Save button by settings its disabled DOM property to false.

Then the code wires the click event handler of the Save button. The code inside the click event handler forms a JavaScript object to store the Employee details. It does so by grabbing the content of all the four <div> elements. It then post this Employee object to the Save() action using jQuery $.post() method. Once the Save() action returns successfully, the Save button is again disabled and the success message returned from the server is shown in a <span> element.

That's it! You can now run the application and test whether editing works as expected.


Bipin Joshi is a software consultant, an author and a yoga mentor having 22+ years of experience in software development. He also conducts online courses in ASP.NET MVC / Core and Design Patterns. He is a published author and has authored or co-authored books for Apress and Wrox press. Having embraced the Yoga way of life he also teaches Meditation and Mindfulness to interested individuals. To know more about him click here.

Get connected : Twitter  Facebook  Google+  LinkedIn

Posted On : 18 November 2014


Tags : ASP.NET MVC jQuery HTML5