Suneditor: (re)Init Error

Created on 6 Jul 2020  路  17Comments  路  Source: JiHong88/SunEditor

Hello,
Here my problem :)

I use sunEditor for one of my dynamic component related to my form builder in vuejs.

The first time when it init it's ok. But when the instance is destroy and when i try to reinitialise it i got :

TypeError: m.fileTags[t].toLowerCase is not a function
at Object._init (suneditor.min.js:9865)
at Object._editorInit (suneditor.min.js:10140)
at A (suneditor.min.js:11737)
at Object.create (suneditor.min.js:11790)
at Object. (suneditor.min.js:11747)
at VueComponent.mounted (js.js:128)
at invokeWithErrorHandling (vue.js:1863)
at callHook (vue.js:4220)
at Object.insert (vue.js:3146)
at invokeInsertHook (vue.js:6341)

But only this error in fact count => suneditor.min.js:9865

It's related to code :

this._fileManager.pluginMap[m.fileTags[t].toLowerCase()] = e

if i put this line into a try catch it's ok.

Do you have any ideas why this line break the init the second time ?

Best regards
( By the way your editor rock!)

bug

All 17 comments

Hi,
Do you use custom plugins when re-creating?

Hello, yes i have a custom plugin, it add a button with functionnality of cleaning the content of the editor.

Please test without custom plugin.
Are you using "fileTags" property in your custom plugin?

My Plugin:

Where id don't use fileTags property :)

var plugin_command = {
                name: 'customCommand',
                display: 'command',

                add: function(core, targetElement)
                {
                    var context = core.context;
                    var rangeTag = core.util.createElement('div');

                    context.customCommand = {
                        targetButton: targetElement,
                        tag: rangeTag
                    };
                },

                active: function(element)
                {
                    return false;
                },

                action: function()
                {
                    this.setContents('');
                    this.context.element.originElement.trigger("validate");
                }
            };

and the plugin in config :

"plugins": [plugin_command],
                "buttonList": [
                    [
                        {
                            name: 'customCommand',
                            dataCommand: 'customCommand',
                            buttonClass: '',
                            title: '' + this.getLabel(this.$root, "RTE_CLEAR_BTN") + '',
                            dataDisplay: 'command',
                            innerHTML: '<i class="xse-icon-add icon-empty"></i>'
                        }

This issue is not reproduce.
Please show the options and codes currently in use.

Here the code :)

            var plugin_command = {
                name: 'customCommand',
                display: 'command',

                add: function(core, targetElement)
                {
                    var context = core.context;
                    var rangeTag = core.util.createElement('div');

                    context.customCommand = {
                        targetButton: targetElement,
                        tag: rangeTag
                    };
                },

                active: function(element)
                {
                    return false;
                },

                action: function()
                {
                    this.setContents('');
                    this.context.element.originElement.trigger("validate");
                }
            };

this.editor = SUNEDITOR.create((_Qs("[name='" + this.name + "_" + this.fieldUid + "']")),
            {
                "toolbarWidth": "100%",
                "resizingBar": false,
                "showPathLabel": false,
                "height": "auto",
                "minHeight": "150px",
                "lang": SUNEDITOR_LANG['' + (this.$root.config.lg.short).toLocaleLowerCase() + ''],
                "plugins": [plugin_command ],
                "buttonList": [
                    [
                        {
                            name: 'customCommand',
                            dataCommand: 'customCommand',
                            buttonClass: '',
                            title: '' + this.getLabel(this.$root, "RTE_CLEAR_BTN") + '',
                            dataDisplay: 'command',
                            innerHTML: '<i class="xse-icon-add icon-empty"></i>'
                        }
                    ],
                    ['undo', 'redo'],
                    ['bold', 'underline', 'italic', 'strike', 'subscript', 'superscript'],
                    ['fontColor', 'hiliteColor'],
                    ['removeFormat'],
                    ['outdent', 'indent'],
                    ['align', 'horizontalRule', 'list'],
                    ['table', 'link'],
                    ['fullScreen', 'showBlocks']
                ]
            });

I hope it could help you.

Best regards
S.

Are there any other actions related to the editor?

Yes, in fact as the sunEditor is created into a Vuejs component, when the component is destroy it also call the "destroy" method of sunEditor.

I have also events attach to the editor => "onload","onchange","onkeyDown","onKeyup" and "onPaste".

the entire code of the component

Rte = Vue.component(
    'Rte',
    {
        template: Rte_template,
        props: ['labels', 'name', 'value', 'fieldMode', 'parent_index', 'key2', 'fieldType', 'validations', 'resetBtn', 'behaviours', 'defaultValue', 'propStatus', 'config', 'styles'],
        mixins: [DynaForm_Mixin, Labels_Mixin, Validation_Mixin, Require_Mixin, Behaviour_Mixin, Prop_Status_Mixin, Guideline_Mixin, Value_Mixin, Event_Mixin, Helper_Mixin, Config_Mixin, Watchers_Mixin],
        data: function()
        {
            return {
                "editor": "",
                "binaryLength": "",
                "updateContent": true,
                "default_config": "rte"
            };
        },
        watch:
        {
            "status_ability": function()
            {
                if (this.status_ability === true)
                {
                    this.editor.enabled();
                    this.editor.toolbar.show();
                }
                else
                {
                    this.editor.disabled();
                    this.editor.toolbar.hide();
                }
            }
        },
        computed:
        {
            customLabels: function(x)
            {
                return [
                    this.getLabel(this.$root, "RTE_LIMIT_REACH")
                ];
            }
        },
        mounted: function()
        {
            //  CUSTOM PLUGIN TO CREATE CLEAR BUTTON
            var that = this;

            //  IF FROM IS ON DISPLAY MODE SO WE DON'T NEED TO INIT PLUGIN
            if (this.isDisplayMode())
            {
                return true;
            }

            var plugin_command = {
                name: 'customCommand',
                display: 'command',

                add: function(core, targetElement)
                {
                    var context = core.context;
                    var rangeTag = core.util.createElement('div');

                    context.customCommand = {
                        targetButton: targetElement,
                        tag: rangeTag
                    };
                },

                active: function(element)
                {
                    return false;
                },

                action: function()
                {
                    this.setContents('');
                    this.context.element.originElement.trigger("validate");
                }
            };
            /* --- */

            //  INIT EDITOR RELATED TO NAME REF OF TEXTAREA
            // this.editor = SUNEDITOR.create((document.querySelector("[name='" + this.name + "_" + this.fieldUid + "']")),
            this.editor = SUNEDITOR.create((_Qs("[name='" + this.name + "_" + this.fieldUid + "']")),
            {
                "toolbarWidth": "100%",
                "resizingBar": false,
                "showPathLabel": false,
                "height": "auto",
                "minHeight": "150px",
                "lang": SUNEDITOR_LANG['' + (this.$root.config.lg.short).toLocaleLowerCase() + ''],
                "plugins": [plugin_command ],
                "buttonList": [
                    [
                        {
                            name: 'customCommand',
                            dataCommand: 'customCommand',
                            buttonClass: '',
                            title: '' + this.getLabel(this.$root, "RTE_CLEAR_BTN") + '',
                            dataDisplay: 'command',
                            innerHTML: '<i class="xse-icon-add icon-empty"></i>'
                        }
                                          ],
                    ['undo', 'redo'],
                    ['bold', 'underline', 'italic', 'strike', 'subscript', 'superscript'],
                    ['fontColor', 'hiliteColor'],
                    ['removeFormat'],
                    ['outdent', 'indent'],
                    ['align', 'horizontalRule', 'list'],
                    ['table', 'link'],
                    ['fullScreen', 'showBlocks']
                ]
            });

            //  CHECK STATUS
            if (this.status_ability === false)
            {
                this.editor.disabled();
                this.editor.toolbar.hide();
            }

            //  EVENTS
            //  ---- ONLOAD
            this.assignEventOnload();
            //  ---- ONCHANGE
            this.assignEventOnChange();
            //  ---- ONKEYDOWN
            this.assignEventOnKeyDown();
            //  ---- ONKEYUP
            this.assignEventOnKeyUp();
            //  ---- ONPASTE
            this.assignEventOnPaste();

            //  INIT COUNTER
            this.calculateCounter();

            //  IF INSIDE REPEATER WE RUN THIS EVENT TO BE ABLE TO REMOVE ALL COMPONENTS DECLARATION TO AVOID MEMORY LEAKS
            /*
            if (typeof this.$parent.formData === "undefined")
            {
                this.$parent.$parent.$on('event_destroyComponents', this.destroy);
            }
            */
        },
        methods:
        {
            "calculateCounter": function()
            {
                this.binaryLength = this.editor.getContents().BLENGTH();
            },
            /*
                EVENTS
            */
            "assignEventOnload": function()
            {
                var that = this;
                var fctOnLoad = function(that, r) {};
                this.editor.onload = fctOnLoad.bind(null, that);
            },
            "assignEventOnChange": function()
            {
                var that = this;

                var fctOnChange = function(that, contents)
                {
                    //  IF WE REACH THE MAXIMUM NOTICE IS DISPLAY
                    if (that.editor.getContents().BLENGTH() > parseInt(that.builded_config.max))
                    {
                        that.editor.noticeOpen('' + that.customLabels[0] + '');
                        that.updateContent = false;
                        that.updateToTextArea("");
                        that.editor.save();
                    }
                    else
                    {
                        that.editor.noticeClose();
                        that.updateContent = true;
                    }

                    if (that.updateContent === true)
                    {
                        that.editor.save();
                        that.updateToTextArea(contents);
                        that.$el.querySelector("textarea").trigger("validate");
                    }
                    that.binaryLength = that.editor.getContents().BLENGTH();
                };

                this.editor.onChange = fctOnChange.bind(null, that);
            },
            "assignEventOnKeyDown": function()
            {
                var that = this;

                var fctKeyDown = function(that, e)
                {
                };
                this.editor.onKeyDown = fctKeyDown.bind(null, that);
            },
            "assignEventOnKeyUp": function()
            {
                var that = this;
                var fctOnKeyUp = function(that)
                {
                    that.binaryLength = that.editor.getContents().BLENGTH();

                    //  IF WE REACH THE MAXIMUM NOTICE IS DISPLAY
                    if (that.editor.getContents().BLENGTH() > parseInt(that.builded_config.max))
                    {
                        that.editor.noticeOpen('' + that.customLabels[0] + '');
                        that.updateContent = false;
                        that.updateToTextArea("");
                    }
                    else
                    {
                        that.editor.noticeClose();
                        that.updateContent = true;
                    }
                };

                this.editor.onKeyUp = fctOnKeyUp.bind(null, that);
            },
            "assignEventOnPaste": function()
            {
                var that = this;
                var fctOnPaste = function(that, clipboard, pastedContent)
                {
                };

                this.editor.onPaste = fctOnPaste.bind(null, that);
            },
            /*
                UPDATE
            */
            "updateToTextArea": function(c)
            {
                if (c === "<p><br></p>")
                {
                    c = "";
                }

                this.setDataValue("" + c + "", true);
            },
            /*
                DESTROY
            */
            "destroy": function()
            {
                this.editor.destroy();
            }
        }
    }
);

I tested it in my view project, but it doesn't give any errors.
What version are you using?

Try using the npm. example
import suneditor from 'suneditor'

When is the "destroy" method of the "Ret" component called?

Are you using like this?

<template>
  <Ret>
</template>

After hard debugging i found why sunEditor return me an error but it's really weird.

If i add an array prototype called "_move" like that :

Array.prototype._move = function(from, to)
{
    this.splice(to, 0, this.splice(from, 1)[0]);
};

I got an error when i try to reinit sunEditor

But if i set my prototype like that :

Object.defineProperty(Array.prototype, '_move',
{
    value: function(from, to)
    {
        this.splice(to, 0, this.splice(from, 1)[0]);
    }
});

No errors :)

Array.prototype._move = ..:
When traversing an array, it is defined as an openable attribute.
"_Move" appears during all array loop.

Object.defineProperty : (enumerable = default value is false):
It is added to the prototype, but is not listed.

It's my mistake.
I'll modify the array loop for in.

Thanks ;)
By the way, you do a great job with sunEditor.

The 2.31.1 version has been updated.
If this issue has not been resolved, please reopen this issue.
Thank you ;)

As the Terminator said : "No problemo" :)

Was this page helpful?
0 / 5 - 0 ratings