54

When a divs value is changed, how Can I trigger an event?

<div class="changeable" contenteditable="true"> Click this div to edit it <div>

So when its content changes I want to create an alert and/or do other things:

$('.changeable').text().change(function() {
  alert('Handler for .change() called.');
});
johnmosly
  • 555
  • 1
  • 4
  • 4

12 Answers12

52

Just store the contents to a variable and check if it is different after blur() event. If it is different, store the new contents.

var contents = $('.changeable').html();
$('.changeable').blur(function() {
    if (contents!=$(this).html()){
        alert('Handler for .change() called.');
        contents = $(this).html();
    }
});

example: http://jsfiddle.net/niklasvh/a4QNB/

Niklas
  • 29,752
  • 5
  • 50
  • 71
22

You can simply use focus/blur event with data() function of jQuery :

// Find all editable content.
$('[contenteditable=true]')
    // When you click on item, record into data("initialText") content of this item.
    .focus(function() {
        $(this).data("initialText", $(this).html());
    });
    // When you leave an item...
    .blur(function() {
        // ...if content is different...
        if ($(this).data("initialText") !== $(this).html()) {
            // ... do something.
            console.log('New data when content change.');
            console.log($(this).html());
        }
    });
});

UPDATE: With Vanilla JS

// Find all editable content.
var contents = document.querySelectorAll("[contenteditable=true]");
[].forEach.call(contents, function (content) {
    // When you click on item, record into `data-initial-text` content of this item.
    content.addEventListener("focus", function () {
        content.setAttribute("data-initial-text", content.innerHTML);
    });
    // When you leave an item...
    content.addEventListener("blur", function () {
        // ...if content is different...
        if (content.getAttribute("data-initial-text") !== content.innerHTML) {
            // ... do something.
            console.log("New data when content change.");
            console.log(content.innerHTML);
        }
    });
});
Bruno J. S. Lesieur
  • 3,612
  • 2
  • 21
  • 25
  • 1
    +1 for being the only solution to my (unposted) question "how can you detect when editing begins?"... so you can display a save button etc... All related questions are focused on detecting change, not the start of the editing session... – A2D Sep 28 '15 at 21:01
  • +1 for showing how to deal with all editable elements without having to reference the id specifically. Works great to create a simple editable grid with an html table. – artifex_knowledge May 04 '18 at 15:18
  • Very useful when the edit in html table triggers an ajax call !! – Marco Giuliani Mar 27 '22 at 22:00
16

the best solution to this currently is the HTML5 input event

<div contenteditable="true" id="content"></div>

in your jquery.

$('#content').on('input', (e) => {
    // your code here
    alert('changed')
});
Canaan Etai
  • 3,455
  • 2
  • 21
  • 17
12

I built a jQuery plugin to do this.

(function ($) {
    $.fn.wysiwygEvt = function () {
        return this.each(function () {
            var $this = $(this);
            var htmlold = $this.html();
            $this.bind('blur keyup paste copy cut mouseup', function () {
                var htmlnew = $this.html();
                if (htmlold !== htmlnew) {
                    $this.trigger('change')
                }
            })
        })
    }
})(jQuery);

You can simply call $('.wysiwyg').wysiwygEvt();

You can also remove / add events if you wish

Blowsie
  • 40,239
  • 15
  • 88
  • 108
8

It's more simple to do it using EventListener (not a jQuery method):

document.getElementById("editor").addEventListener("input", function() {
   alert("input event fired");
}, false);
VasG
  • 123
  • 1
  • 5
  • 3
    This is good for recent Mozilla and WebKit browsers but sadly isn't supported for `contenteditable` in any version fo IE or Opera. – Tim Down May 09 '13 at 08:40
  • this can also be used with jquery for easier attchment to classes, $('.class').on('input', function(){}) – haz0rd Jan 20 '14 at 22:23
6

This is my approach...

$('.changeable').focusout(function() {
  alert('Handler for .change() called.');
});
2

Yet another version in jquery. View in jsFiddle here.

var $editableContent = $("#mycontent");

//  Implement on text change
$editableContent.on("focus", function(event) {$(this).data("currentText", $(this).text());});

$editableContent.on("blur", function (event) {
        if ($(this).text() != $(this).data("currentText")) {
                $(this).trigger('change');}});


//  Wire onchange event
$editableContent.on("change", function(){alert("Text changed to: " + $(this).text())});
dcapelo
  • 79
  • 3
2

function myFunction(){
  alert('Handler for .change() called.');
}
<div class="changeable" contenteditable="true" onfocusout="myFunction()" > Click this div to edit it <div>
πter
  • 1,899
  • 2
  • 9
  • 23
  • Thanks mate. your solution helped me – fahim152 Mar 28 '20 at 16:29
  • When I use your code on table cell, where I want to modify one particular column value, the alert goes on infinite. I used onfocus and onfocusout, same thing happens. All I want is to capture the new value when I move to new cell above or below. onchange does not work either. – AbuTaareq Aug 12 '20 at 00:40
1

Here is a jquery-version:

function fix_contenteditableOnchange(obj)
{
     div=$(obj);
     var contents = div.html();
     var onchange = div.attr('onchange');
     div.blur(function() {
      if (contents!=$(this).html()){
        eval(onchange);
        fix_contenteditableOnchange(obj);
      }
     });
}

Try this out.

KreepN
  • 8,528
  • 1
  • 40
  • 58
Sven
  • 11
  • 1
1

In chrome and maybe in other browsers there is bug, when user presses tab it will create space and append apple-be span or some thing like that.. to remove that user

var contents = $('.changeable').html();
$('.changeable').blur(function() {
   if (contents!=$(this).html()){
 alert('Handler for .change() called.');
      $(".Apple-tab-span").remove();
       contents = $(this).html();
       contentsTx = $(this).text();
       alert(contentsTx);

   }
});

This will remove the span.. it same as above code just modified it little, or u can add

.Apple-tab-span
{
  Display:None;
}

and this will also solve problem .. http://jsfiddle.net/a4QNB/312/

Just modified @Nikals answer ...

nikunjM
  • 560
  • 1
  • 7
  • 21
0

Another solution which is slightly modified version of previous ones but it may be more comfortable to use for some of you.

Idea is to save origin value and compare it with current value in 'blur' event. I save origin value as attribute of editable div tag (instead of creating variable for origin value). Using attribute as container for origin value is more comfortable when one has a huge number of editable divs in table (as cells). So it is easy to get origin value since you don't need to create many variables.

See my complete example code:

editable div

<td><div contenteditable="true" class="cell" origin="originValue">originValue</div></td>

detecting changes in blur

var cells = $("#table").find('td>div[contenteditable=true]');

cells.each(function () {    

        $(this).blur(function() {

                    if ($(this).text() != $(this).attr("origin")) {
                        console.log('changed');
                    }
        });    
});
Bronek
  • 10,722
  • 2
  • 45
  • 46
  • This is not a good approach. Your originalValue may have invalid html but browsers will always try to fix it in editable div, so even when content has not actually changes, your test condition will fail because browser has converted your
    to
    – Vishal Seth Sep 19 '14 at 22:59
  • Here in the future I've used data tags for this purpose and they work great! – Scott Fraley Jul 21 '17 at 18:05
0

(EDIT: DOMSubtreeModified is deprecated.)


What you have to do is make a conjunction of blur and DOMSubtreeModified events on your contenteditable elements.

var contentEdited = false;

function fn($el) {
  if (contentEdited) {
    var text = $el[0].innerText.trim();
    console.log(text);
    contentEdited = false;
  }
}
$("div.editable").on("blur", function() {
  fn($(this));
}).on("DOMSubtreeModified", function() {
  contentEdited = true;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="editable" contenteditable="true">Click this div to edit it<div>
ashleedawg
  • 20,365
  • 9
  • 72
  • 105
Dan Philip Bejoy
  • 4,321
  • 1
  • 18
  • 33
  • `DOMSubtreeModified` [going to go away eventually](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Mutation_events) and therefore should probably be avoided in most cases. It can also drastically slow down DOM performance. – Tim Down Apr 24 '17 at 15:26
  • This event has been deprecated - https://developer.mozilla.org/en-US/docs/Archive/Events/DOMSubtreeModified – sarkiroka Apr 20 '20 at 12:45