Inline Editing

Contact Us or call 1-877-932-8228
Inline Editing

Inline Editing

Sometimes it is nice to be able to edit a page without displaying form elements by default. For example, if you want to allow people who are logged in as administrators to edit sections of a page, you could make it so that the administrator could click on those sections to turn them into form elements.

To view the demo, first:

  1. From the command line (on a PC) or terminal (on a Mac), navigate to the directory MoreAjaxApplications/Demos/.
  2. Type npm install to load the required Node.js modules.
  3. Type npm start to start the server.
  4. Open http://localhost:8080/Presidents in a browser to view the page

Our example below shows a simple table showing the presidents' first and last names:Table with Presidents' First and Last Names

The neat thing about this table is that the names become editable when double clicked:Names Editable Table

All the user has to do is type a new value and tab out or click anywhere else in the document to change the value in the table. An XMLHttpRequest is used to change the record in the database.

This page is generated by the Node.js response route /Presidents in MoreAjaxApps/Demos/server.js and rendered by the MoreAjaxApps/Demos/Presidents.jade template. The server-side code queries the "Presidents" database to retrieve a list of all presidents' IDs, first and last names, and bios, and returns those data as an HTML table.

The code queries the database for the presidents' first and last names and biographies (taken from the Whitehouse website) and then iterates through the result set creating a table row for each president. Each td element has the editable class.

The Jade template includes a call to MoreAjaxApps/Demos/inline-editing.js, which does the real work:

Code Sample:

MoreAjaxApps/Demos/inline-editing.js
function enableEditing() {
	var editableElems = getElementsByClassName(document, "editable");
	var numElems = editableElems.length;
	for (var i = 0; i < numElems; i++) {
		observeEvent(editableElems[i], "dblclick", editElem);
	}
}

function editElem(e) {
	var target = getTarget(e);
	var input;
	var textLen = target.innerHTML.length;
	if (textLen > 30) {
		target.innerHTML = "<textarea cols='120' rows='6'>" + target.innerHTML + "</textarea>";
	} else {
		target.innerHTML = "<input value='" + target.innerHTML + "'>";
	}
	var input = target.firstChild;
	input.select();
	observeEvent(input, "blur", saveCell);
}

function saveCell(e) {
	var target = getTarget(e);
	var td = target.parentNode;
	var tr = td.parentNode;
	var field = td.title;
	var value = target.value;
	var pid = tr.id;

	var xmlhttp = new XMLHttpRequest();
	xmlhttp.open("POST", "SaveCell", true);
	xmlhttp.onreadystatechange = function() {
		if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
			td.innerHTML = target.value;
			blinkText(td, 1000, "Saved", "Normal");
		}
	}
	xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
	xmlhttp.send("field=" + field + "&value=" + value + "&pid=" + pid);
}

function blinkText(elem, time, on, off, timePast) {
	var timePast = timePast + 100 || 0;
	if (hasClassName(elem, on)) {
		removeClass(elem, on);
	} else {
		addClass(elem, on);
	}

	if (timePast < time) {
		setTimeout(function() {
			blinkText(elem, time, on, off, timePast)
		}, 100);
	} else {
		removeClass(elem, on);
		removeClass(elem, off);
	}
}

This is the JavaScript library. It has the following functions:

  • enableEditing()
    1. Gets all the elements with the "editable" class using the getElementsByClassName() function from lib.js and attaches the editElem() function to their double-click events.
  • editElem()
    1. Changes the innerHTML of the double-clicked td to an input or textarea tag (depending on the length of the innerHTML) and attaches the saveCell() function to its change event.
  • saveCell()
    1. Uses Ajax to send the field, value and president id to SaveCell.jsp, which updates the record.
    2. The inline callback function changes the innerHTML of the td to the new value and calls blinkText().
  • blinkText()
    1. Toggles the class name of the passed in element (elem) between the passed-in on and off values for timePast milliseconds. This creates a blinking effect.

The contenteditable Attribute

HTML5 includes a contenteditable attribute that can be applied to almost any element, though Internet Explorer does not allow it on elements that make up tables (e.g, table, tr, td, etc.). Editing contenteditable content in the browser can be tricky/quirky when nested tags are involved, but it is pretty simple (and cool) when you are dealing with straight text.

To run the demo, first start the Node.js server if it isn't already running: navigate from the command line/terminal to MoreAjaxApps/Demos/ and type npm start. Then browse to http://localhost:8080/contenteditable.html.

The code is simple:

Code Sample:

MoreAjaxApps/Demos/contenteditable.html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Content Editable</title>
</head>
<body>
<p contenteditable="true" style="font-size:xx-large">I am editable.</p>
</body>
</html>

All you have to do to make an element editable is add contenteditable="true" to the tag. The screenshot below shows the page after the user has clicked in the paragraph and entered the word "truly." User Has Clicked

Although contenteditable wasn't added to the specification until HTML5, it is well supported by browsers in use today - even Internet Explorer 6.

Of course, when the user changes content on the page that doesn't have any permanent effect. You, as the developer, have to catch that change and do something about it. When a editable element loses focus, a blur event is triggered (there is no change event). You can use the blur event to trigger Ajax code that saves any changes the user made. Run the following example to see how it works:

Code Sample:

MoreAjaxApps/Demos/contenteditable-blur.html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Content Editable</title>
<script type="text/javascript" src="lib.js"></script>
<script type="text/javascript">
	observeEvent(window, "load", function() {
		var p1 = document.getElementById("p1");
		observeEvent(p1, "blur", function(e) {
			var target = getTarget(e);
			alert(target.innerHTML);
		});
	});
</script>
</head>
<body>
<p id="p1" style="font-size:xx-large" contenteditable="true">I am editable.</p>
</body>
</html>
Next