CKEditor实例已经存在


99

我正在使用jquery对话框来呈现表单(通过AJAX获取)。在某些表格上,我正在使用CKEditor来编写文本区域。编辑器在第一次加载时显示正常。

当用户取消对话框时,我将删除内容,以便在以后的请求中重新加载它们。问题是,一旦重新加载对话框,CKEditor就会声称该编辑器已经存在。

uncaught exception: [CKEDITOR.editor] The instance "textarea_name" already exists.

该API包括一种销毁现有编辑器的方法,我见过有人声称这是一种解决方案:

if (CKEDITOR.instances['textarea_name']) {
CKEDITOR.instances['textarea_name'].destroy();
}
CKEDITOR.replace('textarea_name');

这对我不起作用,因为我收到一个新错误:

TypeError: Result of expression 'i.contentWindow' [null] is not an object.

该错误似乎发生在“ destroy()”而不是“ replace()”上。有没有人遇到过这种情况并找到了不同的解决方案?

是否可以“重新渲染”现有编辑器,而不是销毁并替换它?

更新 这里是另一个处理相同问题的问题,但是他提供了一个可下载的测试用例

Answers:


101

为此,您需要在销毁实例时传递布尔参数true

    var editor = CKEDITOR.instances[name];
    if (editor) { editor.destroy(true); }
    CKEDITOR.replace(name);

2
“ true”选项使所有事情有所不同。还值得一提的是,下面给出的“ CKEDITOR.remove(instance)”答案不是一个好的解决方案,因为它是一个内部API,它也会产生错误,因此最好使用instance.destroy(true)
Bala Clark

谢谢,这确实帮助了我。
2012年

6
参加感谢者的合唱团!我喜欢Stack Overflow总是只用一次搜索就能解决我所有的问题。
TommiForsström,2012年

1
这个答案是如此有用,我很惊讶它被深深地埋在这里。
Petr Vostrel 2013年

2
应该有一个选择,可以根据收到的票数对答案进行排序。
shasi kanth 2013年

28
function loadEditor(id)
{
    var instance = CKEDITOR.instances[id];
    if(instance)
    {
        CKEDITOR.remove(instance);
    }
    CKEDITOR.replace(id);
}

这让我有些悲痛,但是您的解决方案有所帮助。谢谢!
Ben Scheirman 2010年

我在firefox中遇到了类似的问题,该问题在页面上有三个CKEditor实例,第一个没有显示,但是另外两个在其中,我添加了上面的代码,现在所有的编辑器都出现了
Craig Angus 2010年

18
不要使用CKEDITOR.remove,因为它只会从数组中清除元素,而将所有DOM保留在内存中。在文档中指出,它仅供内部使用:docs.cksource.com/ckeditor_api/symbols/CKEDITOR.html#.remove如madhaviaddanki所述,您应该改为使用instace.destroy()。
AlfonsoML 2010年

2
遇到相同的情况,并且如上所述,此答案是错误的。如下所述,使用destroy()并传递true参数最终对我有用。
Mathachew 2012年

19

我也有这个问题,但是我用一种简单得多的方法解决了它。

我在jQuery脚本中使用“ ckeditor”类作为选择器,希望将其文本区域用于CKEditor。默认的ckeditor JS脚本也使用此类来标识要用于CKEditor的文本区域。

这意味着我的jQuery脚本和默认的ckeditor脚本之间存在冲突。

我只是将textarea的类和我的jQuery脚本更改为“ do_ckeditor”(您可以使用除“ ckeditor”之外的任何内容),并且它可以正常工作。


谢谢,是的,“自动” ckeditorizing也弄乱了我。另请参见stackoverflow.com/a/3631391/923817
D.Tate 2013年

11

这是对我有用的最简单(也是唯一)的解决方案:

if(CKEDITOR.instances[editorName])
   delete CKEDITOR.instances[editorName];
CKEDITOR.replace(editorName);

在数组中删除该条目可防止此表单安全检查破坏您的应用程序。

destroy()和remove()对我不起作用。


1
这也是与我合作的唯一解决方案,感谢您发布!
迈克尔·罗宾逊

我确实有destroy()工作。但是都没有deletedestroy()完全清除编辑器实例。像字典和其他相关对象之类的东西仍然会潜伏。
ADU

我尝试过instance.destroy(true),但是对我来说不起作用。但这对我有用。谁能告诉我,这有副作用吗?
亚历克斯(Alex)2015年

7

也许这会帮到您-我使用jquery做过类似的事情,除了我正在加载未知数量的ckeditor对象。我花了一段时间才发现这一点-文档中不清楚。

function loadEditors() {
    var $editors = $("textarea.ckeditor");
    if ($editors.length) {
        $editors.each(function() {
            var editorID = $(this).attr("id");
            var instance = CKEDITOR.instances[editorID];
            if (instance) { instance.destroy(true); }
            CKEDITOR.replace(editorID);
        });
    }
}

这是我从编辑器获取内容的方法:

    var $editors = $("textarea.ckeditor");
    if ($editors.length) {
        $editors.each(function() {
            var instance = CKEDITOR.instances[$(this).attr("id")];
            if (instance) { $(this).val(instance.getData()); }
        });
    }

更新:我已更改答案以使用正确的方法-.destroy()。.remove()应该是内部的,并且在某一点上没有正确记录。


这似乎已消除了错误,但是在第二次渲染时,textarea现在包含“ null”,并且我无法再与工具栏或textarea进行交互。如果我确实单击工具栏按钮,则会收到类似以下的错误:“ TypeError:表达式'this。$。focus'的结果[未定义]不是函数”-或者-“ TypeError:表达式'this.document.getWindow()的结果。$'[undefined]不是对象”。您在哪里/什么时候调用该函数?我的脚本内联了jquery加载的内容。(ckeditor.js位于父html的头部)
jackboberg,2009年

在将所有文本区域添加到页面并填充内容后,我将其称为。
ScottE

5

我遇到过类似的问题,我们为通过ajax加载的内容制作了CKeditor的多个实例。

CKEDITOR.remove()

将DOM保留在内存中,并且没有删除所有绑定。

CKEDITOR.instance [instance_id] .destroy()

每当我使用来自ajax的新数据创建新实例时,都给出错误i.contentWindow错误。但这只是直到我确定清除DOM后要销毁实例。

页面上存在实例及其DOM时使用destroy(),那么它工作得很好。


5

对于ajax请求,

 for(k in CKEDITOR.instances){
    var instance = CKEDITOR.instances[k];
    instance.destroy()
 }
  CKEDITOR.replaceAll();

这将删除文档中的所有实例。然后创建新实例。



3

i.contentWindow is null不再与DOM中绑定到textarea的编辑器实例上调用destroy时,似乎发生了错误。

CKEDITORY.destroy接受参数noUpdate

APIdoc指出:

如果实例正在替换DOM元素,则此参数指示是否使用实例内容更新该元素。

因此,为避免该错误,请在从DOM中删除textarea元素之前调用destroy,或者调用destory(true)以避免尝试更新不存在的DOM元素。

if (CKEDITOR.instances['textarea_name']) {
   CKEDITOR.instances['textarea_name'].destroy(true);
}

(将版本3.6.2与jQuery适配器一起使用)


3

这对我有用:

for(name in CKEDITOR.instances)
{
  CKEDITOR.instances[name].destroy()
}

确保您的“取消”代码调用与此类似的内容!我的问题是我的取消并未称为destroy :)
ROunofF

2
CKEDITOR.instances = new Array();

在调用创建实例(每页加载一个)之前,我正在使用它。不知道这如何影响内存处理,什么不影响。仅当您要替换页面上的所有实例时,这才起作用。


1
我尝试了此页面上的所有解决方案...对于我的环境,这是唯一可行的解​​决方案(但在仅ie9的FF中无法正常工作)...不确定为什么其他方法却无法使用,但一小时后反复试验,这是唯一对我有用的解决方案。感谢您发布此安德鲁。
Ronedog

2

我已经根据上述所有代码准备了自己的解决方案。

      $("textarea.ckeditor")
      .each(function () {

                var editorId = $(this).attr("id");

                try {    
                    var instance = CKEDITOR.instances[editorId];
                    if (instance) { instance.destroy(true); }

                }
                catch(e) {}
                finally {
                    CKEDITOR.replace(editorId);
                }
            });

它非常适合我。

有时在AJAX请求之后,错误的DOM结构。对于实例:

<div id="result">
   <div id="result>
   //CONTENT
   </div>
</div>

这也将导致问题,并且ckEditor将不起作用。因此,请确保您具有正确的DOM结构。


2

我的实例也遇到了同样的问题,我四处寻找,最后这个实现对我有用:



    //set my instance id on a variable

    myinstance = CKEDITOR.instances['info'];

    //check if my instance already exist

    if (myinstance) { 
        CKEDITOR.remove(info)
    }

    //call ckeditor again

    $('#info').ckeditor({
        toolbar: 'Basic',
        entities: false,
        basicEntities: false
    });

2

您可以通过ckeditor的remove方法删除任何ckeditor实例。实例将是ID或文本区域的名称。

if (CKEDITOR.instances[instance_name]) {
    CKEDITOR.remove(CKEDITOR.instances[instance_name]);
}

1

实际上,从您的代码中删除“ .ckeditor”类可以解决此问题。我们大多数人都遵循ckeditor文档中的jQuery集成示例:

$('.jquery_ckeditor')
.ckeditor( function() { /* callback code */ }, { skin : 'office2003' } );

并以为“ ...也许我可以摆脱掉或'.jquery_'部分”。

我一直在浪费时间调整回调函数(因为{skin:'office2003'}实际上起作用),而问题出在其他地方。

我认为文档应该提到不建议将“ ckeditor”用作类名,因为它是保留关键字。

干杯。


1

我知道了

删除CKEDITOR.instances [editorName];

单独删除实例。我已阅读和看到的所有其他方法,包括在此处从其用户的stackoverflow中找到的方法,均不适用于我。

在我的情况下,即时通讯使用ajax调用来提取包裹在和周围的内容的副本。问题恰好是因为我正在使用jQuery .live事件绑定“编辑此文档”链接,然后在ajax加载成功后应用ckeditor实例。这意味着,当我单击另一个链接与另一个.live事件的链接时,我必须使用delete CKEDITOR.instances [editorName]作为清除内容窗口(保留表单),然后重新获取所保留内容的任务的一部分在数据库或其他资源中。


1

我在jQuery对话框中遇到了同样的问题。

如果只想删除以前的数据,为什么要破坏实例?

function clearEditor(id)
{
  var instance = CKEDITOR.instances[id];
  if(instance)
  {
    instance.setData( '' );
  }
}

1

我选择重命名所有实例,而不是销毁/替换-因为有时加载AJAX的实例并不能真正代替页面核心上的那个实例……在RAM中保留了更多实例,但是这种方式减少了冲突。

    if (CKEDITOR && CKEDITOR.instances) {
        for (var oldName in CKEDITOR.instances) {
            var newName = "ajax"+oldName;
            CKEDITOR.instances[newName] = CKEDITOR.instances[oldName];
            CKEDITOR.instances[newName].name = newName;
            delete CKEDITOR.instances[oldName];
        }
    }

1

在这种情况下,我必须控制生成对话框的控件,每个控件都需要在这些对话框中嵌入ckeditor。碰巧文本区域共享相同的ID。(通常这是非常不好的做法,但是我有2个jqGrid,一个分配的项目,另一个未分配的项目。)它们共享几乎相同的配置。因此,我使用通用代码来配置两者。

因此,当我加载对话框时,可以从jqGrid中添加行或进行编辑。我必须在所有文本区域中删除所有CKEDITOR实例。

$('textarea').each(function()
{
    try 
    {
        if(CKEDITOR.instances[$(this)[0].id] != null)
        {
            CKEDITOR.instances[$(this)[0].id].destroy();
        }
    }
    catch(e)
    {

    }
});

这将遍历所有文本区域,如果存在CKEDITOR实例,则将其销毁。

或者,如果您使用纯jQuery:

$('textarea').each(function()
{
    try 
    {
        $(this).ckeditorGet().destroy();
    }
    catch(e)
    {

    }
});


0

在接收到空引用异常时,我遇到了同样的问题,并且在编辑器中将显示单词“ null”。我尝试了几种解决方案,包括将编辑器升级到3.4.1均无济于事。

我最终不得不编辑源代码。在_source \ plugins \ wysiwygarea \ plugin.js中的第416至426行处,有一个如下代码段:

iframe = CKEDITOR.dom.element.createFromHtml( '&lt;iframe' + ... + '></iframe>' );

至少在FF中,iframe并没有在需要的时候完全实例化。我在该行之后用setTimeout函数包围了其余函数:

iframe = CKEDITOR.dom.element.createFromHtml( '<iframe' + ... + '></iframe>' );
setTimeout(function()
{ 
    // Running inside of Firefox chrome the load event doesn't bubble like in a normal page (#5689)
    ...
}, 1000);

};

// The script that launches the bootstrap logic on 'domReady', so the document
...

现在,文本在模式对话框中呈现一致。


0

为了支持表单的动态(Ajax)加载(没有页面刷新),其中包含具有相同(再次调用相同表单)或不同ID(先前已卸载表单)的文本区域的文本区域,并将它们转换为CKEditor元素,我执行了以下操作(使用JQuery适配器):

页面完成每个传递要转换的textarea的Ajax调用之后,我将调用以下函数:

setupCKeditor()

看起来像这样(假设您的textareas将被转换为RTE的具有class =“ yourCKClass”):

    /* Turns textAreas into TinyMCE Rich Text Editors where
 * class: tinymce applied to textarea.
 */
function setupCKeditor(){

    // define editor configuration      
    var config = {skin : 'kama'};

    // Remove and recreate any existing CKEditor instances
    var count = 0;
    if (CKEDITOR.instances !== 'undefined') {
        for(var i in CKEDITOR.instances) {

            var oEditor   = CKEDITOR.instances[i];
            var editorName = oEditor.name;

             // Get the editor data.
            var data = $('#'+editorName).val();

            // Check if current instance in loop is the same as the textarea on current page
            if ($('textarea.yourCKClass').attr('id') == editorName) {
                if(CKEDITOR.instances[editorName]) {

                    // delete and recreate the editor
                    delete CKEDITOR.instances[editorName];
                    $('#'+editorName).ckeditor(function() { },config);
                    count++;

                }
            }   


        }
    }

    // If no editor's exist in the DOM, create any that are needed.             
    if (count == 0){

        $('textarea.yourCKClass').each( function(index) {

                var editorName = $(this).attr('id');
                $('#'+editorName).ckeditor(function() { $('#'+editorName).val(data); },config);

            });

    }


}

我应该提到这一行:

$('#'+editorName).ckeditor(function() { $('#'+editorName).val(data); },config);

可以(并且应该)简单地:

$('#'+editorName).ckeditor(function() { },config);

但是我发现编辑器在加载后通常会显示正确的内容一秒钟,并且清空编辑器中所需的内容。因此,带有回调代码的行会强制CKEditor内容与原始textarea内容相同。使用时引起闪烁。如果可以避免使用它,请这样做。


0

我遇到了像杰克伯格一样的问题。我正在使用动态表单加载到jquery对话框中,然后附加各种小部件(datepickers,ckeditors等)。我尝试了上面提到的所有解决方案,但没有一个对我有用。

由于某种原因,ckeditor仅在我第一次加载表单时才附加,第二次我收到与jackboberg完全相同的错误消息。

我分析了我的代码,发现如果将ckeditor附加在“空中”时,即表单内容仍未放入对话框中,则ckeditor将无法正确附加其绑定。那是因为ckeditor附加在“空中”,第二次将它附加在“空中” ... poof ...由于第一个实例未从DOM中正确删除,因此引发错误。

这是我的代码导致错误:

var $content = $(r.content); // jQuery can create DOM nodes from html text gotten from <xhr response> - so called "mid-air" DOM creation
$('.rte-field',$content).ckeditor(function(){});
$content.dialog();

这是有效的修复程序:

var $content = $(r.content).dialog(); // first create dialog
$('.rte-field',$content).ckeditor(function(){}); // then attach ckeditor widget

0

我碰到了同样的事情,问题是wordcount插件初始化花费的时间太长。30+秒。用户将单击显示ckeditor的视图,然后取消,从而将新页面ajax加载到dom中。该插件抱怨是因为在准备将自身添加到contentWindow时,iframe或任何contentWindow指向的对象不再可见。您可以通过单击进入视图,然后等待“字数统计”出现在编辑器的右下角中来对此进行验证。如果立即取消,则不会有问题。如果不等待它,将会得到i.contentWindow为null错误。要修复它,只需废弃插件:

if (CKEDITOR.instances['textarea_name']) 
{
   CKEDITOR.instances['textarea_name'].destroy();
}
CKEDITOR.replace('textarea_name', { removePlugins: "wordcount" } );

如果需要字计数器,请使用对字进行计数的功能在编辑器上注册粘贴和键入事件。


0

对于那些使用jquery“ adapter”并遇到麻烦的人(就像我以前一样),超级hackish可行的解决方案是执行以下操作:

// content editor plugin
(function($){
    $.fn.contentEditor = function( params ) {
        var xParams = $.extend({}, $.fn.contentEditor.defaultParams, params);
        return this.each( function() {   
            var $editor = $(this);
            var $params = $.extend({}, xParams, $editor.data());

            // if identifier is set, detect type based on identifier in $editor
            if( $params.identifier.type ) {
                $params.type = $editor.find($params.identifier.type).val();
            }

            $editor.data('type', $params.type);

            // edit functionality
            editButton = $('<button>Edit Content</button>').on('click',function(){
                // content container
                var $cc = $('#' + $editor.data('type'));

                // editor window
                var $ew = $('<form class="editorWindow" />');
                $ew.appendTo('body');

                // editor content
                $ec = $('<textarea name="editorContent" />').val($cc.html());
                $ec.appendTo($ew);
                $ec.ckeditor();


                //$ec.ckeditorGet().setMode('source');


                $ew.dialog({
                    "autoOpen": true,
                    "modal": true,
                    "draggable": false,
                    "resizable": false,
                    "width": 850,
                    "height": 'auto',
                    "title": "Content Editor",
                    "buttons": { 
                        'Save': function() {                            
                            $cc.html( $ec.val() );
                            $ec.ckeditorGet().destroy(); 
                            $ew.remove();
                        },
                        'Cancel / Close': function() { 

                            $ec.ckeditorGet().destroy();                        
                            $ew.remove();
                        }
                    },
                    'close': function() {
                        $ec.ckeditorGet().destroy(); 
                    },
                    'open': function() {
                        $ew.find('a.cke_button_source').click();

                        setTimeout(function(){
                            $ew.find('a.cke_button_source.cke_on').click();
                        }, 500);
                    }
                });

                return false;
            });

            editButton.appendTo( $editor );

        });
    }

    // set default option values
    $.fn.contentEditor.defaultParams = {
        'identifier': {
            'type': 'input[name="type"]'
        }
    };   

})(jQuery);   

$(function(){

    $('form.contentEditor').contentEditor();

});

关键是这一部分:

                'open': function() {
                    $ew.find('a.cke_button_source').click();

                    setTimeout(function(){
                        $ew.find('a.cke_button_source.cke_on').click();
                    }, 500);
                }

这解决了下次打开对话框时编辑器文本不可见的问题。我意识到这非常骇人听闻,但考虑到其中大多数将用于管理工具,因此我认为这不会像往常那样令人担忧。.并且这种方法有效,因此希望它将为某人节省一些时间时间 ;)


0

这是jquery .load()api和ckeditor的完全正常工作的代码,在我的情况下,我正在将具有ckeditor的页面加载到具有某些jquery效果的div中。希望对您有帮助。

 $(function() {
            runEffect = function(fileload,lessonid,act) {
            var selectedEffect = 'drop';
            var options = {};
            $( "#effect" ).effect( selectedEffect, options, 200, callback(fileload,lessonid,act) );
        };
        function callback(fileload,lessonid,act) {
            setTimeout(function() {//load the page in effect div
                $( "#effect" ).load(fileload,{lessonid:lessonid,act:act});
                 $("#effect").show( "drop", 
                          {direction: "right"}, 200 );
                $("#effect").ajaxComplete(function(event, XMLHttpRequest, ajaxOptions) {
                    loadCKeditor(); //call the function after loading page
                });
            }, 100 );   
        };

        function loadCKeditor()
        {//you need to destroy  the instance if already exist
            if (CKEDITOR.instances['introduction']) 
            {
                CKEDITOR.instances['introduction'].destroy();
            }
            CKEDITOR.replace('introduction').getSelection().getSelectedText();
        }
    });

===================== button for call the function ================================

<input type="button" name="button" id="button" onclick="runEffect('lesson.php','','add')" >

0

非常简单。就我而言,我运行了以下jquery方法,该方法将在页面加载期间销毁ckeditor实例。这可以解决问题并解决了问题-

jQuery方法-

function resetCkEditorsOnLoad(){

    for(var i in CKEDITOR.instances) {
        editor = CKEDITOR.instances[i];
            editor.destroy();
            editor = null;
    }
}

$(function() {

            $(".form-button").button();
    $(".button").button();

    resetCkEditorsOnLoad(); // CALLING THE METHOD DURING THE PAGE LOAD

            .... blah.. blah.. blah.... // REST OF YOUR BUSINESS LOGIC GOES HERE

       });

而已。希望对您有帮助。

干杯,Sirish。


0

此功能在CKEditor 4.4.5版中对我有用,它没有任何内存泄漏

 function CKEditor_Render(CkEditor_id) {
        var instance = CKEDITOR.instances[CkEditor_id];
        if (CKEDITOR.instances.instance) {
            CKEDITOR.instances.instance.destroy();
        }
        CKEDITOR.replace(CkEditor_id);
    }

//如下调用此函数

var id = 'ckeditor'; // Id of your textarea

CKEditor_Render(id);

0

CKeditor 4.2.1

这里有很多答案,但对我来说我还需要更多(有点脏,所以如果有人可以改善,请这样做)。对我来说,我的问题所在是MODAL。

我使用Foundation在模式中渲染CKEditor。理想情况下,我在关闭时会销毁编辑器,但是我不想惹上Foundation。

我叫delete,尝试了remove和另一种方法,但这是我最终解决的问题。

我正在使用textarea而不是DIV进行填充。

我的解决方案

//hard code the DIV removal (due to duplication of CKeditors on page however they didn't work)

    $("#cke_myckeditorname").remove();


     if (CKEDITOR.instances['myckeditorname']) {
                delete CKEDITOR.instances['myckeditorname'];
                CKEDITOR.replace('myckeditorname', GetCKEditorSettings());
            } else {
                CKEDITOR.replace('myckeditorname', GetCKEditorSettings());
            }

这是我返回您特定格式的方法,您可能不希望这样做。

    function GetCKEditorSettings()
    {
       return {
                    linkShowAdvancedTab: false,
                    linkShowTargetTab: false,
                    removePlugins: 'elementspath,magicline',
                    extraAllowedContent: 'hr blockquote div',
                    fontSize_sizes: 'small/8px;normal/12px;large/16px;larger/24px;huge/36px;',
                    toolbar: [
                        ['FontSize'],
                        ['Bold', 'Italic', 'Underline', '-', 'NumberedList', 'BulletedList', '-', 'Link', 'Unlink'],
                        ['Smiley']
                    ]
                };
    }

0

试试这个:

for (name in CKEDITOR.instances)
{
    CKEDITOR.instances[name].destroy(true);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.