This posting is regards [email protected] loaded with [email protected].
Although there are a couple of articles on SO with this question I believe this is still an open question. Please do not mark this posting as a duplicate.
To replicate problem: 1) instantiate a DOM element with the ckeditor directive. 2) navigate away from the view in such a way that the Angular Component that is hosting the ckeditor is destroyed. You get this in the Javascript console:
ckeditor.js:19 [CKEDITOR] Error code: editor-destroy-iframe.
There is a closed bug on github over this with no apparent or acceptable solution, unless I missed it. If there is a solution there we should document it on this post because it is incomplete or obscure.
The problem is apparently that Angular framework destroys the iframe element before the ckeditor itself is destroyed. This causes the diagnostic message.
One proposed solution involves the use of a plugin called divarea. From what I understand this replaces the iframe with a div element. The reason this is problematic is that the CSS elements from the hosting page will be mixed in with the CSS that CKEDITOR uses.
Another proposed solution involves the following snippet of code:
for (name in CKEDITOR.instances) {
CKEDITOR.instances[name].destroy(true);
}
This SO posting mentions this and asks for where this code can be inserted. There is no Angular lifecycle event that seems to work. Even if it did this would not be an acceptable fix because it destroys all CKEDITOR instances and in my application there might be more than one on the page that might survive a router event.
Along those lines I discovered that I can find "my" CKEDITOR instance in my Angular Component with these steps. In the template:
<ckeditor id="content"
#editor
[(ngModel)]="editorContent"
[config]="{}"
debounce="500"
name="content"
></ckeditor>
Which is standard except for the #editor directive which establishes a local variable. Then in the component you can build a method like this:
declare const CKEDITOR: any;
@Component() ....
@ViewChild('editor') ckeditor: CKEditorComponent;
destroyEditor() {
var name = this.ckeditor.instance.name;
CKEDITOR.instances[name].destroy(true);
}
So the question is: where to call the destroyEditor function? (Other question is whether the destroy(true) method is the right one to call.)
Calling it from ngOnDestroy does not work. Catching an event from the router hasn't worked either. Any other suggestions?
I am using Angular 6 and here is what I did.
I programmatically destroy the iFrame using this
Please Note: I did not want any editor present so I destroyed them all. Its import to note, that if a user is navigating away from, and back to a CKEDITOR you have destroyed a new instance will be created. (editor2...3...4...5 etc) I did not care about the instance int so I destroyed them all and let angular create new instances as it needed based on user interaction.
destroyEditor(){
let editor = window['CKEDITOR'];
if(editor.instances){
for(var editorInstance in editor.instances){
editor.instances[editorInstance].destroy();
}
}
}
This will allow you to destroy the iframe on any exit condition you have. When a user navigates away from the editor, I call this right before I set my value that changes the UI view and completes the navigation away from the editor.
You will notice at this point you are still getting an error in the console from ckeditor.component.js
Make this change in the following file.
\node_modules\ng2-ckeditor\lib\src\ckeditor.component.js
This will check for the instance name specifically and not attempt a destroy... because.. you already destroyed it.
CKEditorComponent.prototype.ngOnDestroy = function () {
var _this = this;
//if (this.instance) {
if(CKEDITOR.instances[_this.instance.name]) {
setTimeout(function () {
_this.instance.removeAllListeners();
CKEDITOR.instances[_this.instance.name].destroy();
_this.instance.destroy();
_this.instance = null;
});
}
};
If modifying JS-files under node_module is not desired, as in my case, call the following function from ngOnDestroy():
public destroyEditor(): void {
const editor = window['CKEDITOR'];
if (editor.instances) {
for (const editorInstance in editor.instances) {
if (editor.instances.hasOwnProperty(editorInstance) &&
editor.instances[editorInstance]) {
editor.instances[editorInstance].destroy();
editor.instances[editorInstance] = {
destroy: () => true,
};
}
}
}
Note, that after destroying, a dummy object is assigned to the collection item to prevent a JS error, when the component is to be destroyed from the native function. The component must implement OnDestroy interface and the destroyEditor() function called like this:
export class RichTextEditorComponent implements OnDestroy {
public ngOnDestroy(): void {
this.destroyEditor();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With