45

I added TinyMCE(version 4.0.2) editor in a existing HTML form in my project(PHP,Codeigniter). My final target is to enable the form submit button if any changes occur in the form including TinyMCE editor. I can do it only with the form except TinyMCE editor. I could not detect TinyMCE changes.

I want to detect if any change occur when key up. I have seen that tinymce has an onchange function like bellow.

            setup : function(ed) {
            ed.onChange.add(function(ed, l) {
                console.debug('Editor contents was modified. Contents: ' + l.content);
            });

I putted upper setup code inside the bellow init function, but no output i have found.

tinymce.init({ });

Can you tell how to detect change, or any better idea?

danronmoon
  • 3,814
  • 5
  • 34
  • 56
user2603482
  • 833
  • 2
  • 8
  • 13

14 Answers14

75

I'm late to the party, but for future reference here is how you do it in TinyMCE 4.X:

tinyMCE.init({
   setup:function(ed) {
       ed.on('change', function(e) {
           console.log('the event object ', e);
           console.log('the editor object ', ed);
           console.log('the content ', ed.getContent());
       });
   }
});
Roger Ramos
  • 568
  • 8
  • 22
sica07
  • 4,896
  • 8
  • 35
  • 54
  • 12
    note that change event will fire only when editor has lost focus ( for write changes) . this should be combine with the next answer. in order to capture format/drag & drop change – oak Sep 23 '14 at 11:21
  • Note that 'change' fires twice during a "session". Once when you press your first key after you have entered the edit field and once after you leave a changed field. – user2587656 Oct 09 '20 at 05:01
37

For Tinymce 4 it works for me,

        editor.on('keyup', function(e) {
            alert('keyup occured');
            //console.log('init event', e);
            console.log('Editor contents was modified. Contents: ' + editor.getContent());
            check_submit(); //another function calling
        });

EDIT:

Note that keyup won't capture all cases. for example copy/paste/cut from menu and not from keyboard

if you want you can capture those with

editor.on('paste', function(e) {
                    console.debug('paste event');

                });

editor.on('cut', function(e) {
                    console.debug('cut event');

                });

NOTE if you capture cut and paste from tinymce you should probably not process those event from keyup. What I did is to do save only if the keys are not keys for cut & paste i.e :

 /**
 * MCE keyup callback, update the master model selected attribute
 * 
 * @method tinyMCEKeyup
 */
 tinyMCEKeyUp : function(e) {
        console.log('tinymce:keyup');


         var ctrlDown = false;
         var ctrlKey = 17, vKey = 86, xKey = 88;


         if ((e.ctrlKey) && (e.keyCode === vKey)) {
             console.log('paste from keyboard')
             /* got here. do nothing. let paste event handle this one  */
             return;
         } else if ((e.ctrlKey) && (e.keyCode === xKey)) {
             console.log('cut from keyboard')
             /* got here. do nothing. let paste event handle this one  */
             return;
         }

         this.doSave();

},

and call this function from the keyup event. This way you will save yourself do some actions twice on cut & paste

NOTE soon you will figure out that any style changes that happens from menu will NOT trigger those event as well..

I'm still looking for an answer to capture style change.

sica07
  • 4,896
  • 8
  • 35
  • 54
user2603482
  • 833
  • 2
  • 8
  • 13
27
let editorChangeHandlerId;
tinymce.init({
    // ...
    setup: function(editor) {
        editor.on('Paste Change input Undo Redo', function () {
            clearTimeout(editorChangeHandlerId);
            editorChangeHandlerId = setTimeout(function() {
                console.log('changed');
            }, 100);
        });
    }
    // ,...
});
jnbm
  • 118
  • 2
  • 4
Nagy Zoltán
  • 659
  • 8
  • 7
  • 3
    Pay attention to this answer, folks. This is probably the best one. It's the only one that truly raises an event immediately when any change is made. – ron Jan 22 '20 at 22:54
  • The problem is that if you want to do something just once, when any kind of input is made ( be it writing, removing, inserting media, etc), this will trigger it multiple times based on the type of event that fits the action. For example, if you have an initial state, and add another word, change + input are both fired, then if you click outside of the box, change is fired again, input gets triggered on every character and so on. I would like an input event but for any kind of input – Petru Lebada Jun 04 '21 at 12:15
  • @Petru Lebada Yes, it would be true, but the timeout function sucks other events because they probably came in 100ms. So your event handler code (in this example the "console.log") runs only once. – Nagy Zoltán Jun 05 '21 at 16:10
  • Tried with a timeout but it still triggers all of them – Petru Lebada Jun 08 '21 at 12:33
  • @Petru Lebada Didn't you declare "editorChangeHandlerId" variable that the setTimeout gives back locally inside the handler function? I modified the snippet to be more clear that the editorChangeHandlerId must be declared somewhere outside. – Nagy Zoltán Jun 09 '21 at 19:07
  • @PetruLebada how about caching the previous value? ```let content; tinymce.init({ setup: function(editor) { editor.on('Paste Change input Undo Redo', function () { const latestContent= editor.getContent(); if (content!== latestContentl) { content = latestContentl; console.log('changed'); } }); } // ,... });``` – Marcel van der Drift May 29 '22 at 20:46
  • just add keyup as well then it will truly be onchange. – Yash Agrawal Oct 08 '22 at 07:43
  • This work for me in all cases. thanks man! – Yousef Oct 22 '22 at 13:06
  • I think you will also need to add `keyup` to handle some special cases with iPad virtual keyboards and to avoid the 100ms latency, you could add some implementation of `throttle` algorithm. It still makes sense to emit your own "changed" event after `setTimeout(..., 0)` to allow the browser native event queue to flush once. – Mikko Rantalainen Nov 18 '22 at 09:56
  • I think we should remove the input because it will also be triggered on focus. – Jamal Dec 13 '22 at 10:36
13

That works for me:

tinyMCE.init({
    setup : function(ed){
         ed.on('NodeChange', function(e){
             console.log('the event object ' + e);
             console.log('the editor object ' + ed);
             console.log('the content ' + ed.getContent());
         });
    }
});

also

ed.on('SaveContent', function(e) {  

or

ed.on('submit', function(e) {

Found on page http://www.tinymce.com/wiki.php/api4:class.tinymce.Editor in Section Event

baacke
  • 781
  • 9
  • 21
Martin
  • 131
  • 1
  • 2
11

The following will capture "keyup" and other change events (copy, paste, center, etc.):

tinymce.init({
    setup: function (ed) {
        ed.on('keyup', function (e) {
            tinyMceChange(ed);
        });
        ed.on('change', function(e) {
            tinyMceChange(ed);
        });
    }
});

function tinyMceChange(ed) {
    console.debug('Editor contents was modified. Contents: ' + ed.getContent());
}
oalbrecht
  • 413
  • 4
  • 11
7

Im using this in tinymce 4.x

tinymce.init({
    selector: "#tinymce-textarea",
    setup : function(ed) {
        ed.on("change", function(e){
            $('#tinymce-livepreview').html(tinymce.activeEditor.getContent());
        });
        ed.on("keyup", function(){
            $('#tinymce-livepreview').html(tinymce.activeEditor.getContent());
        });
   }
});

Explanation:

on("change") is for detect changes on mouse event if u click toolbar icon or selection from the menu. It also able to detect the keyboard event but only after lost focus (not real time).

on("keyup") is for detect changes on real time keyboard event

4

I'm using TinyMCE 5.4.1

I tried with a lot of events at the same time like 'keyup, copy, paste, cut' and someones specific for tables like 'newrow', 'newcell', but what at the end, the combination what really captures all the changes is 'input NodeChange' ( it covers all the cases of the first events and more )

editor.on('input NodeChange', function() {
   console.log('content updated');
});
darkman97i
  • 170
  • 7
3

Try this:

tinyMCE.init({
   setup : function(ed) {
          ed.onChange.add(function(ed, l) {
                  var editorContent = l.content;    // editorContent will hold the values of the editor
                  alert(editorContent);
          });
   }
});

CLick for the Rreference here

Nil'z
  • 7,487
  • 1
  • 18
  • 28
  • I used it, but where to find the result when any change occur. Can you tell me please? – user2603482 Jul 23 '13 at 06:26
  • But when using this code the tinymce editor box disappear. Can you tell please why disappear? – user2603482 Jul 23 '13 at 06:38
  • 2
    I tried it, and my editor box disappeared, too - I think it's because onChange is no longer a function in 4.x. Theoretically, they've replaced it with a similar function named "change", but that's not working for me at all. – Erhannis Aug 30 '13 at 12:56
2

We have found that the change event sometimes only fires after pressing enter; It seems to be tied into the undo processing. Also, the keyup event fires when the contents have not changed, such as when shift or CMD-A are pressed.

So we use both change and keyup, and compare the last processed value to the current value to detect a real change.

This solution also works for cut, and paste, and modifications from menu items.

//Sometimes does not fire unless enter is pressed
editor.on('change', () => {
    var value = editor.getContent();
    if (value !== editor._lastChange) {
        editor._lastChange = value;
        window.console.log(editor._lastChange);
    }
});

//Sometimes fires even if content did not change
editor.on('keyup', () => {
    var value = editor.getContent();
    if (value !== editor._lastChange) {
        editor._lastChange = value;
        window.console.log(editor._lastChange);
    }
});
Steven Spungin
  • 27,002
  • 5
  • 88
  • 78
2

This work fine for me in all condtion key up , cut, copy , paste

    setup: function (editor) {
        editor.on('KeyUp', function(e){
            alert(editor.getContent());
         });
}
Sandeep Sherpur
  • 2,418
  • 25
  • 27
  • Would be useful if it took care of undo and redo as well since those operations also change ur editor content. Like Nagy Zoltáns answer – Craig Jan 28 '20 at 13:58
  • How about copy/cut/paste action via IME or with mouse action which do not use keyboard at all? I think you should use `editor.on('keyup paste change input undo redo', ...)` instead and apply debounce or throttle algorithm to limit excessive events. – Mikko Rantalainen Nov 18 '22 at 10:00
2

The above solutions will not detect whether the tinymce updo button was used. Unfortunately, neither will this, but it is a little more semantically correct.

if (tinymce.activeEditor.isDirty()) {
    alert("Your content is changed.");
}

http://archive.tinymce.com/wiki.php/api4:method.tinymce.Editor.isDirty

user1032531
  • 24,767
  • 68
  • 217
  • 387
0

To detect a form change on the textarea which TinyMCE uses, I am triggering an event on editor.targetElm

setup: function(editor) {
  editor.on('change', function(e){
    editor.targetElm.dispatchEvent(new Event('change'));
  })
},

Now I can listen to the event in form validation or other scripts the usual way

inputElement.onchange = (e) => {
  // do something
};
boris
  • 81
  • 7
0
tinymce.init({
  selector: 'textarea',
  init_instance_callback: function(editor) {
    editor.on('write_your_event', function(e) {
      console.log('The ' + e.command + ' command was fired.');
    });
  }
});

TinyMCE supports the following browser-native events:

beforeinput, blur, click, compositionend, compositionstart, compositionupdate, contextmenu, copy, cut, dblclick, drag, dragdrop, dragend, draggesture, dragover, dragstart, drop, focus, focusin, focusout, input, keydown, keypress, keyup, mousedown, mouseenter, mouseleave, mousemove, mouseout, mouseover, mouseup, paste, reset, submit, touchcancel, touchend, touchmove, touchstart and wheel.

Lee Taylor
  • 7,761
  • 16
  • 33
  • 49
-1

Hi I've tried using this:

setup : function(ed) {
    ed.onChange.add(function() {
        $('#changed').val(1);
    });
}

This is to update a hidden field "changed" with the value of 1 so that when a user tries to close pane or leave page they are informed they have unsaved data.

My fault is that this only works if 2 or more changes are made - for example if I noticed I hadn't finished with a full stop "." went back to add this then for some reason clicked close I would be able to leave the page without being warned of the changes

Gravesy
  • 45
  • 6