inline editing forms with javascript

I have picked up some contracting work to build a new web site. It is very early days and I am just putting together some initial workable web forms at the moment and want something for editing information that would be a little less ugly than just presenting a standard set of populated html form controls. Instead, I like the idea that the information will be written to the page as normal text, but clicking on it will allow you to change the value inline. After a little poking about, there appear to be two main contenders to help implement this in JQuery, Jeditable and Editable.

Feature comparison of Jeditable and Editable JQuery plugins
JeditableEditable
html 5 form elementsnono
extendable input typesyes,
via inbuilt addInputType method
yes,
by modifying the source directly
default POST data formatid:element_id value:element_valuenone

Adding html5 input types

Editable

Editable does at least provide an editableFactory in its source which is intended to be extended. Although easy to do, it still doesn’t get around the fundamental problem of having to modify the source itself.

$.editableFactory = {
	'text': {
		toEditable: function($this,options){
			$('<input/>').appendTo($this)
						 .val($this.data('editable.current'));
		},
		getValue: function($this,options){
			return $this.children().val();
		}
	},
	// adding custom support for <input type="url">
	'url': {
		toEditable: function($this,options){
			$('<input type="url"/>').appendTo($this)
						 .val($this.data('editable.current'));
		},
		getValue: function($this,options){
			return $this.children().val();
		}
	},
	// end of added block
	...

Jeditable

There really is not much in it in terms of complexity or verboseness between the two implementations, but the fact that Jeditable allows extensions without modifying its source swings it for me.

<script type="text/javascript">
    $.editable.addInputType('url', {
        element : function(settings, original) {
            var input = $('<input type="url">');
            $(this).append(input);
            return(input);
        }
    });
</script>

Posting changes back to the server

Both of the following examples work with the following template. You will also notice that this is not plain html, but a velocity template. The template is served from a spring/velocity application, more details of which will follow in later posts.

#springBind("myDomainObject.url")
<span class="editableURL">$status.value</span>

Editable

Although Editable doesn’t support this out of the box, it is pretty straightforward.

<script type="text/javascript">
    $(document).ready(function() {
        $('.editableURL').editable({type:'url', submit:'save', cancel:'cancel', onSubmit:end});
    });

    function end(content) {
        $.post(window.location.href, {url: content.current});
    }
</script>

So we wait for the document to be loaded by the browser, then decorate all elements with the “editableURL” class with Editable’s behaviour. The end function is triggered when you submit your change, and is responsible for POSTing the data back to the server. Note that, in this example, data is POSTed back to the same URL from which the page was served.

All in all, this is rather nice, and we have complete control over the data passed back to our server.

Jeditable

As mentioned in the comparison table above, Jeditable by default will POST data in the format id: element_id, value: element_value. This is fine for table-based data in which every field has an id, but a long way from OK for our domain-object-backed Spring application. The good news is that we get complete control over Jeditable’s POST behaviour, too.

<script type="text/javascript">
    $(document).ready(function() {
        $('.editableURL').editable(function(value, settings) {
            $.post(window.location.href, {url: value});
            return(value);
        }, {submit: 'save', type: 'url'});
    });
</script>

This snippet works broadly the same way, with the added control that the return value of the function is what is used as the new value displayed on the page. I can’t make up my mind whether this is a good thing. As the script stands, if the server encounters an error updating the field, then the new value will be displayed on the page and the user will be none the wiser that anything went wrong.

Conclusion

Although Editable is arguably preferred by Stack Overflow users, there is a little snag with both of them. Neither library seems to handle keyboard navigation particularly well (at least in Chrome on OS X). Editable’s submit and cancel buttons do nothing when they are triggered by receiving focus and hitting the spacebar, whereas Jeditable’s support is better in that the buttons do work, just that you have to be quick about it. If you leave the focus on the button for more than a second or so then it assumes you have given up and cancels the edit, taking away the form control again.

All in all, Jeditable seems to suit my preferences a little better. Its public revision control and nicer web site also make it seem just that little bit more polished. The only negative point, and it is a small one, is that Jeditable doesn’t provide a labelled version number. Judging by the readme on github it is up to version 1.7.2 at the time of writing, so that is the number I inserted into the filename myself before using it.

<!DOCTYPE html>
<html>
    <head>
        <title>Inline editing forms with JQuery and Jeditable</title>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
        <script src="/{your_path_here}/jquery.jeditable-1.7.2.mini.js" type="text/javascript"></script>
    </head>
    <body>
        #springBind("myDomainObject.url")
        <span class="editableURL">$status.value</span>
        
        <script type="text/javascript">
            $.editable.addInputType('url', {
                element : function(settings, original) {
                    var input = $('<input type="url">');
                    $(this).append(input);
                    return(input);
                }
            });
        </script>

        <script type="text/javascript">
            $(document).ready(function() {
                $('.editableURL').editable(function(value, settings) {
                    $.post(window.location.href, {url: value});
                    return(value);
                }, {submit: 'save', type: 'url'});
            });
        </script>
        
    </body>
</html>
comments powered by Disqus