Javascript 在CKEditor的instanceReady上调用setReadOnly时会导致错误

Javascript 在CKEditor的instanceReady上调用setReadOnly时会导致错误,javascript,jquery,gwt,backbone.js,ckeditor,Javascript,Jquery,Gwt,Backbone.js,Ckeditor,我试图在实例完全加载后将我的CKEditor实例设置为“readOnly”,但我遇到了一个Javascript错误:无法调用null的方法“setReadOnly”。当我深入研究时,错误来自ckeditor.js中的这一行,在editor.setReadOnly方法中:this.editable().setReadOnly(a)这意味着编辑器存在,但(在CKEditor实例上)方法/属性不存在 下面是我的代码,我会解释一下。我的应用程序是GWT和主干网的组合。CKEditor本身是由主干代码创建

我试图在实例完全加载后将我的CKEditor实例设置为“readOnly”,但我遇到了一个Javascript错误:
无法调用null的方法“setReadOnly”
。当我深入研究时,错误来自ckeditor.js中的这一行,在
editor.setReadOnly
方法中:
this.editable().setReadOnly(a)
这意味着编辑器存在,但(在CKEditor实例上)方法/属性不存在

下面是我的代码,我会解释一下。我的应用程序是GWT和主干网的组合。CKEditor本身是由主干代码创建的,但父元素在GWT中,因此我在那里启动
setEnabled
操作

private native void setEnabledOnLoad(boolean enabled, String id) /*-{
  CKEDITOR.on("instanceReady", function(evt) {
    if(evt.editor.name === id) {
      Namespace.trigger(Namespace.Events.SET_ENABLED, enabled);
    }
  });
}-*/;

setEnabled: function(enabled) {
  this.editor.setReadOnly(!enabled);
  if(enabled){
    this.editor.focusManager.focus();
  } else {
    this.editor.focusManager.blur();
  }
}
主干类有一个用于
Namespace.Events.SET_ENABLED
的侦听器,该侦听器触发
setEnabled

是否还有其他CKEditor事件需要我倾听?
editable
上似乎没有
instancerady
事件。我错过了什么

编辑
this.editor
是在主干类
render
函数中创建的,如下所示:

this.editor = CKEDITOR.replace(this.$(this.id)[0], config);

我之所以不在创建
instancerady
侦听器之后立即添加它,是因为在实例完全初始化之前,在GWT中调用了函数
setEnabledOnLoad
。这是代码位于两个位置的结果。GWT说“好的,创建实例”,但在GWT转到下一行代码并希望将其设置为启用/禁用时主干尚未完成。

您可以尝试通过以下方式订阅
instancerady
事件:

CKEDITOR.instances.editor.on("instanceReady", onInstanceReadyHandler) 
但是,此时必须已经创建了
编辑器
实例(在调试器中检查
CKEDITOR.instances

我对
editable
editor
之间的区别有点困惑。你能把你的代码片段显示在
this.editor
this.editable
被分配的地方吗

[编辑]我想我知道发生了什么
CKEDITOR
是一个全局对象,您可以将其视为一个包含所有CKEDITOR实例的类。尝试使用
CKEDITOR.on
处理事件是不对的,您需要在特定实例上执行此操作(如上面所示)。我假设,“editor”是您要将
CKEDITOR
实例附加到的父元素的ID(如果我错了,请纠正我)。我不熟悉主干,但通常是通过以下方式完成的:


这里,我们将CKEDITOR的一个新实例附加到
编辑器
父元素,同时订阅
instancerady
事件。返回的对象
editorInstance
应提供您可能需要的所有内容,包括。您还可以使用父元素ID通过全局
CKEDITOR
对象访问它,即
CKEDITOR.instances.editor
。另一方面,更确切地说,它是一个在上可用的服务对象。我想不出任何具体的情况下,您可能需要直接使用它。

两年后,但这里是我的解决方案。也许其他人会发现它很有用。 如上所述,事件似乎是在完全设置editable()函数之前触发的,因此一种解决方案是,在将其设置为只读之前,只需等待它完成。这可能是一个丑陋的方式,但它的工作

        //Delayed execution - ckeditor must be properly initialized before setting readonly
        var retryCount = 0;
        var delayedSetReadOnly = function () {
            if (CKEDITOR.instances['bodyEditor'].editable() == undefined && retryCount++ < 10) {
                setTimeout(delayedSetReadOnly, retryCount * 100); //Wait a while longer each iteration
            } else {
                CKEDITOR.instances['bodyEditor'].setReadOnly();
            }
        };
        setTimeout(delayedSetReadOnly, 50);
//延迟执行-在设置readonly之前,必须正确初始化ckeditor
var-retryCount=0;
var delayedSetReadOnly=函数(){
if(CKEDITOR.instances['bodyEditor'].editable()==undefined&&retryCount++<10){
setTimeout(delayedSetReadOnly,retryCount*100);//每次迭代都要等待更长的时间
}否则{
CKEDITOR.instances['bodyEditor'].setReadOnly();
}
};
setTimeout(delayedSetReadOnly,50);

很抱歉,我从未用我的解决方案更新此内容。我需要将GWT函数与CKEditor行为进一步解耦。因此,我在GWT“setEnabled”中添加了一个函数,当父对象想要更新CKEditor对象的启用状态时,会从父对象调用该函数

public void setEnabled(boolean enabled) {
    this.enabled = enabled;
    toggleCKEditorEnabled(enabled);     
}       
然后将上面引用的函数“setEnabledOnLoad”更改为“ToggleEdit或ENABLED”,这将触发具有
启用值的SET_ENABLED事件

我没有将侦听器附加到CKEditor的特定实例,而是将其添加到主干MessageEntryView类中,该类是CKEditor实例的容器。在MessageEntryView的
initialize
函数中,我添加了这一行

Namespace.on(Namespace.Events.SET_ENABLED, this.setEnabled);

这仅仅是因为我在任何给定的时间都在屏幕上加载了一个CKEditor实例。这个问题及其解决方案使我们无法一次向页面添加更多的CKEditor实例,这是我们在继续使用主干网替换整个客户端之前讨论的问题。

CKEditor
确实保存了所有实例,但它也做了更多。我没有将
instancerady
侦听器添加到实例的原因是在创建实例之前调用了函数
setEnabledLoad
。这是代码位于两个位置的结果。GWT说了“好的,创建实例”,但当GWT转到下一行代码并希望将其设置为启用/禁用时,主干还没有完成。我承认我对主干和GWT缺乏适当的知识,无法进一步理解我的答案:]希望有人能加入进来。不敢相信你必须这样做,但上面的代码确实有效。
Namespace.on(Namespace.Events.SET_ENABLED, this.setEnabled);