42

I am trying to get the ckeditor working. Obviously it doesn't make use of the textarea so on submit the form doesn't submit the text in the editor. Beceause I make use of polymorphic associations etc. I can't make a onsubmit function to get the value of the textarea (when the form is submitted) .

So I found this question: Using jQuery to grab the content from CKEditor's iframe

with some very good answers. The answers posted there keep the textarea up to date. That is very nice and just what I need! Unfortunately I can't get it to work. Does somebody know why (for example) this doesn't work?

I have a textarea (rails but it just translates to a normal textarea):
<%= f.text_area :body, :id => 'ckeditor', :rows => 3 %>

And the following js:

if(CKEDITOR.instances.ckeditor ) {
  CKEDITOR.remove(CKEDITOR.instances.ckeditor);
}
CKEDITOR.replace( 'ckeditor',
{
skin : 'kama',
toolbar :[['Styles', 'Format', '-', 'Bold', 'Italic', '-', 'NumberedList', 'BulletedList', 'Link']]});


CKEDITOR.instances["ckeditor"].on("instanceReady", function()
{
//set keyup event
this.document.on("keyup", CK_jQ);

//and paste event
this.document.on("paste", CK_jQ);
}

function CK_jQ()
{
 CKEDITOR.instances.ckeditor.updateElement(); 
}

I get the following "error" in my firebug.
missing ) after argument list [Break on this error] function CK_jQ()\n

Community
  • 1
  • 1
heldopslippers
  • 828
  • 2
  • 9
  • 20

11 Answers11

122

Before submit do:

for(var instanceName in CKEDITOR.instances)
    CKEDITOR.instances[instanceName].updateElement();
Code Maverick
  • 20,171
  • 12
  • 62
  • 114
xtds
  • 2,453
  • 2
  • 19
  • 12
  • But the OP already calls updateElement all the time and it still didn't work for OP, that's possibly why this isn't the answer here. – Joel Peltonen Sep 13 '12 at 13:05
  • @Nenotlep: the accepted answer is basically the same but is a workaround for my answer since CKEDITOR already provides that with updateElement – xtds Sep 19 '12 at 09:16
  • @sldev: I agree that your solution is better, I was trying to point out that he already called updateElement() in his solution, although in a not so logical as your place before submit :) – Joel Peltonen Sep 19 '12 at 09:35
  • 1
    Works great. What beats me is why CKEditor's default save action does not work this way. – András Szepesházi May 31 '13 at 09:04
  • Don't forget `if (CKEDITOR.instances.hasOwnProperty(instanceName)) {` – zanderwar Aug 21 '19 at 01:19
55

have you figured it out?

I'm using CKEditor version 3.6.1 with jQuery form submit handler. On submit the textarea is empty, which to me is not correct. However there is an easy workaround which you can use, presuming all your CKEditor textareas have the css class ckeditor.

$('textarea.ckeditor').each(function () {
   var $textarea = $(this);
   $textarea.val(CKEDITOR.instances[$textarea.attr('name')].getData());
});

Execute the above before you do your submit handling ie. form validation.

T. Junghans
  • 11,385
  • 7
  • 52
  • 75
  • Same solution for prototype: `$$('textarea._cke').each( function(T) { T.update( CKEDITOR.instances[T.id].getData() ); } );` – Eduard7 Oct 18 '11 at 08:27
  • @TJ- I am new in Jquery, I dont know how it works ? Could you please write a line of code that alerts the value of ckeditor ? i am trying with :- `alert($textarea.val(CKEDITOR.instances[$textarea.attr('name')].getData()));` . Please... – Bajrang Feb 15 '12 at 06:33
  • @J.J. Before you alert assign the jquery object of your textarea to $textarea. `var $textarea = $('textarea.mytextarea');` Then use `alert(CKEDITOR.instances[$textarea.attr('name')].getData())`. Do this after the ckeditor has been applied. – T. Junghans Feb 15 '12 at 07:41
  • Thanks, saved me a lot of time – NightMICU Feb 24 '12 at 00:24
  • I think you have to use $textarea.html() instead of .val() – Alex Angelico Feb 26 '12 at 16:37
  • getData() and val() work perfectly fine, but see answer by sldev where he uses CKEDITOR's updateElement(). – Ben Amada May 22 '12 at 02:04
  • after loading editor by replace, you may add this line >>> CKEDITOR.instances.textAreaClientId.on('blur', function(){CKEDITOR.instances.textAreaClientId.updateElement();}); – Mhmd Jul 13 '13 at 12:13
  • I had to use: $('textarea.ckeditor').each(function () { var $textarea = $(this); $textarea.val(CKEDITOR.instances[$textarea.attr('id')].getData()); }); The instance was named by the fields ID not name. But it seems a more supported solution as mentioned above by Ben Amada is: for ( instance in CKEDITOR.instances ) CKEDITOR.instances[instance].updateElement(); – Mark Jul 18 '13 at 05:10
  • Just in case anyone reading this needs to do it for FCKeditor, the cases are different: `$(this).val(FCKeditorAPI.Instances[this.id].GetData());` –  Jul 23 '13 at 16:19
  • This is quite useful if you want to Encode the HTML before it goes into the textarea – JDandChips Apr 29 '15 at 10:41
10

Combination of all of the above answers into one.

Create a new custom.js file and add this:

CKEDITOR.on('instanceReady', function(){
  $.each( CKEDITOR.instances, function(instance) {

    CKEDITOR.instances[instance].on("instanceReady", function() {
      this.document.on("keyup", CK_jQ);
      this.document.on("paste", CK_jQ);
      this.document.on("keypress", CK_jQ);
      this.document.on("blur", CK_jQ);
      this.document.on("change", CK_jQ);
    });
  });

});

function CK_jQ() {
  for ( var instance in CKEDITOR.instances ) { CKEDITOR.instances[instance].updateElement(); }
}

You don't have to worry about the name of the textarea, just add a class ckeditor in the textarea, the above and you are done.

Vladislav Rastrusny
  • 29,378
  • 23
  • 95
  • 156
JohnDel
  • 2,092
  • 8
  • 35
  • 64
10

Thanks @JohnDel for the info, and i use onchange to make it update every change.

CKEDITOR.on('instanceReady', function(){
   $.each( CKEDITOR.instances, function(instance) {
    CKEDITOR.instances[instance].on("change", function(e) {
        for ( instance in CKEDITOR.instances )
        CKEDITOR.instances[instance].updateElement();
    });
   });
});
Kenny Ong
  • 401
  • 6
  • 18
  • 1
    I wish CKEDITOR did this by default, i can't really see any reason not to? – t.mikael.d Jan 11 '15 at 17:01
  • 1
    `instanceReady` is triggered for every editor instance that you have. So if you have multiple instances *this will bind the `onChange` event multiple times* doing a lot of unnecessary work. Instead of the `$.each(...)` you should use make use of [the event parameter](http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.html#event:instanceReady) that is provided to the `instanceReady` callback and take its `editor` attribute which is the editor instance that has just called its `instanceReady` event. – flu Feb 16 '15 at 16:59
  • This one also works on multiple textareas, loaded by ajax and using CKEDITOR.replace('item', language). – AllThisOnAnACER Jun 11 '18 at 17:35
6

ADD Function JavaScript for Update

function CKupdate() {
  for (instance in CKEDITOR.instances)
    CKEDITOR.instances[instance].updateElement();
}

It's work. Cool

ˈvɔlə
  • 9,204
  • 10
  • 63
  • 89
Donot Don't
  • 609
  • 7
  • 12
2

Just Add

CKEDITOR.instances.textAreaClientId.on('blur', function(){CKEDITOR.instances. textAreaClientId.updateElement();});

where textAreaClientId is your instance name

Regards

Mhmd
  • 4,989
  • 3
  • 22
  • 29
1
CKEDITOR.instances["ckeditor"].on("instanceReady", function()
{
//set keyup event
this.document.on("keyup", CK_jQ);

//and paste event
this.document.on("paste", CK_jQ);
})
anonymous
  • 37
  • 1
1

I just increase that to the response of T.J. and worked for me:

$("form").on("submit", function(e){
    $('textarea.ckeditor').each(function () {
       var $textarea = $(this);
       $textarea.val(CKEDITOR.instances[$textarea.attr('name')].getData());
    });
});
0

On load:

$(function () {
  setTimeout(function () {
    function CK_jQ(instance) {
      return function () {
        CKEDITOR.instances[instance].updateElement();
      };
    }

    $.each(CKEDITOR.instances, function (instance) {
      CKEDITOR.instances[instance].on("keyup", CK_jQ(instance));
      CKEDITOR.instances[instance].on("paste", CK_jQ(instance));
      CKEDITOR.instances[instance].on("keypress", CK_jQ(instance));
      CKEDITOR.instances[instance].on("blur", CK_jQ(instance));
      CKEDITOR.instances[instance].on("change", CK_jQ(instance));
    });
  }, 0 /* 0 => To run after all */);
});
Eduardo Cuomo
  • 17,828
  • 6
  • 117
  • 94
0

There have been some API changes with the latest versions of CKEditor, so here's an answer for CKEditor 5:

let ckeditor;

// Create a CKEditor, and store its handle someplace that you may
// access later. In this example, we'll use the `ckeditor` variable:
ClassicEditor
  .create(document.querySelector("textarea"), {})
  .then(editor => { ckeditor = editor; });

// When your form submits, use the `updateSourceElement` method
// on the editor's handle:
document.querySelector("form").addEventListener("submit", function() {
  ckeditor.updateSourceElement();
});

To my knowledge, CKEditor does this automatically when you submit a form, so this particular example shouldn't actually do anything. But it is useful when you need the content of the textarea to udpate without submitting the form that contains it.

Michael
  • 1,357
  • 3
  • 15
  • 24
-2

All above answer are focusing on how to fix this error but I want to take the answer on what cause me this error

I had a

<textarea class="ckeditor" rows="6" name="Cms[description]"></textarea>

changed to

<textarea class="ckedit" rows="6" name="Cms[description]"></textarea>

I changed class attribute value to anything other than ckeditor and boom error gone.

Hope that help

Kuldeep Dangi
  • 4,126
  • 5
  • 33
  • 56