contenteditable change events

0 votes
asked Sep 7, 2009 by jourkey

I want to run a function when a user edits the content of a div with contenteditable attribute. What's the equivalent of an onchange event?

I'm using jQuery so any solutions that uses jQuery is preferred. Thanks!

16 Answers

0 votes
answered Jan 7, 2009 by cms

The onchange event doesn't fires when an element with the contentEditable attribute is changed, a suggested approach could be to add a button, to "save" the edition.

Check this plugin which handles the issue in that way:

0 votes
answered Sep 11, 2009 by tim-down

I'd suggest attaching listeners to key events fired by the editable element, though you need to be aware that keydown and keypress events are fired before the content itself is changed. This won't cover every possible means of changing the content: the user can also use cut, copy and paste from the Edit or context browser menus, so you may want to handle the cut copy and paste events too. Also, the user can drop text or other content, so there are more events there (mouseup, for example). You may want to poll the element's contents as a fallback.

UPDATE 29 October 2014

The HTML5 input event is the answer in the long term. At the time of writing, it is supported for contenteditable elements in current Mozilla (from Firefox 14) and WebKit/Blink browsers, but not IE.

Demo: http://jsfiddle.net/ch6yn/

0 votes
answered Jan 9, 2010 by joox

To avoid timers and "save" buttons, you may use blur event wich fires when the element loses focus. but to be sure that the element was actually changed (not just focused and defocused), its content should be compared against its last version. or use keydown event to set some "dirty" flag on this element.

0 votes
answered Jan 17, 2010 by lawrence-whiteside

Check this idea out. http://pastie.org/1096892

I think it's close. HTML 5 really needs to add the change event to the spec. The only problem is that the callback function evaluates if (before == $(this).html()) before the content is actually updated in $(this).html(). setTimeout don't work, and it's sad. Let me know what you think.

0 votes
answered Sep 13, 2010 by dennkster

I have modified lawwantsin 's answer like so and this works for me. I use the keyup event instead of keypress which works great.

$('#editor').on('focus', function() {
  before = $(this).html();
}).on('blur keyup paste', function() { 
  if (before != $(this).html()) { $(this).trigger('change'); }
});

$('#editor').on('change', function() {alert('changed')});
0 votes
answered Sep 5, 2011 by user740433

Here is the solution I ended up using and works fabulously. I use $(this).text() instead because I am just using a one line div that is content editable. But you may also use .html() this way you dont have to worry about the scope of a global/non-global variable and the before is actually attached to the editor div.

$('body').delegate('#editor', 'focus', function(){
    $(this).data('before', $(this).html());
});
$('#client_tasks').delegate('.task_text', 'blur', function(){
    if($(this).data('before') != $(this).html()){
        /* do your stuff here - like ajax save */
        alert('I promise, I have changed!');
    }
});
0 votes
answered Sep 7, 2011 by balupton

Here is a more efficient version which uses on for all contenteditables. It's based off the top answers here.

In CoffeeScript using jQuery:

$('body')
    .on 'focus', '[contenteditable]', ->
        $this = $(this)
        $this.data 'before', $this.html()
        return $this
    .on 'blur keyup paste input', '[contenteditable]', ->
        $this = $(this)
        if $this.data('before') isnt $this.html()
            $this.data 'before', $this.html()
            $this.trigger('change')
        return $this

In JavaScript using jQuery:

$('body').on('focus', '[contenteditable]', function() {
    var $this = $(this);
    $this.data('before', $this.html());
    return $this;
}).on('blur keyup paste input', '[contenteditable]', function() {
    var $this = $(this);
    if ($this.data('before') !== $this.html()) {
        $this.data('before', $this.html());
        $this.trigger('change');
    }
    return $this;
});

The project is here: https://github.com/balupton/html5edit

0 votes
answered Sep 28, 2011 by gregory-whiteside

Here's what worked for me:

   var clicked = {} 
   $("[contenteditable='true']").each(function(){       
        var id = $(this).attr("id");
        $(this).bind('focus', function() {
            // store the original value of element first time it gets focus
            if(!(id in clicked)){
                clicked[id] = $(this).html()
            }
        });
   });

   // then once the user clicks on save
   $("#save").click(function(){
            for(var id in clicked){
                var original = clicked[id];
                var current = $("#"+id).html();
                // check if value changed
                if(original != current) save(id,current);
            }
   });
0 votes
answered Jan 28, 2012 by janfabian

Using DOMCharacterDataModified under MutationEvents will lead to the same. The timeout is setup to prevent sending incorrect values (e.g. in Chrome I had some issues with space key)

var timeoutID;
$('[contenteditable]').bind('DOMCharacterDataModified', function() {
    clearTimeout(timeoutID);
    $that = $(this);
    timeoutID = setTimeout(function() {
        $that.trigger('change')
    }, 50)
});
$('[contentEditable]').bind('change', function() {
    console.log($(this).text());
})

JSFIDDLE example

0 votes
answered Sep 21, 2012 by tracend

This thread was very helpful while I was investigating the subject.

I've modified some of the code available here into a jQuery plugin so it is in a re-usable form, primarily to satisfy my needs but others may appreciate a simpler interface to jumpstart using contenteditable tags.

https://gist.github.com/3410122

Update:

Due to its increasing popularity the plugin has been adopted by Makesites.org

Development will continue from here:

https://github.com/makesites/jquery-contenteditable

Welcome to Q&A, where you can ask questions and receive answers from other members of the community.
Website Online Counter

...