editor.js icon indicating copy to clipboard operation
editor.js copied to clipboard

Editor.destroy()

Open Doaa-Ahmed opened this issue 6 years ago • 13 comments

I want to destroy the editor instance manually and then set it again when the component is updated. I am using ReactJs but I am not using the react wrapper. Whenever I try to call the destroy function I got the error that destroy is not a function.

const MyEditor = () => {
  const [editor, setEditor] = useState([]);
  useEffect(() => {
    if (editor.length != 0) { 
      editor.destroy();
    }
    setEditor(
      new EditorJS({
        holder: "editor",
        placeholder: "Insert your text here!",
        tools: {
          header: Header,
          list: List,
          quote: Quote,
          checklist: Checklist,
          code: Code,
          table: Table,
          image: {
            class: ImageTool,
            config: {
              endpoints: {
                byFile: "myFile",
                byUrl: "myUrl"
              }
            }
          }
        },
        data: {
          blocks: myBlocks
        }
      })
    );
  }, [myData]);

Doaa-Ahmed avatar Oct 15 '19 09:10 Doaa-Ahmed

Make sure you call destroy() on the editor instance. Try to debug editor variable, looks like it stores something different.

neSpecc avatar Oct 15 '19 09:10 neSpecc

Although I got this when I try to debug the editor variable. t {isReady: Promise} clear: ƒ () configuration: {holder: "editor", placeholder: "Insert your event details here!", tools: {…}, data: {…}, initialBlock: "paragraph", …} destroy: ƒ () emit: ƒ (e, n) focus: ƒ () isReady: Promise {: undefined} off: ƒ (e, n) on: ƒ (e, n) render: ƒ (e) save: ƒ () proto: Object But it then gives me the same error that the destroy is not a function

Doaa-Ahmed avatar Oct 15 '19 09:10 Doaa-Ahmed

Maybe editor is already destroyed?

neSpecc avatar Oct 15 '19 09:10 neSpecc

No. When I run the code it gives me 2 instances of the editor on the page. So, I want the first instance to be destroyed

Doaa-Ahmed avatar Oct 15 '19 09:10 Doaa-Ahmed

Ok we will test it.

neSpecc avatar Oct 15 '19 09:10 neSpecc

if (editor.length != 0) { 
    editor.destroy();
}

Looks like editor is an Array. Try editor[0].destroy()

marvinside avatar Dec 21 '19 20:12 marvinside

any update on this issue? I have the same problem, every time I try to destroy the editor instance, it keeps saying that the destroy is not a function.

elda-mahaindra avatar Jan 02 '20 22:01 elda-mahaindra

you can use it inside isReady editor.isReady .then(() => { // editor.destroy(); /** Do anything you need after editor initialization */ });

mohanagy avatar Jan 03 '20 22:01 mohanagy

For anyone getting this error, editor can not be destroyed while it is loading!

mkeida avatar Jan 14 '20 19:01 mkeida

any updates on this matter?

I have a TypeError when running destroy() on the editor instance.

Unhandled Runtime Error TypeError: Cannot read property 'deactivate' of null

negrudev avatar Oct 15 '20 11:10 negrudev

getting this now with read only mode

evanjmg avatar Apr 22 '21 09:04 evanjmg

I am facing the same issue but i will come up with some solution try this

`"use client"; import React, { useEffect, useState, MutableRefObject } from 'react'; import EditorJS from '@editorjs/editorjs';

interface UpdateEditorProps{ editorRef: MutableRefObject<EditorJS | null> initialData: any }

const Editor = ({ editorRef , initialData}:UpdateEditorProps) => { const [isMounted, setIsMounted] = useState(false);

const initializeEditor = async () => {
     // @ts-ignore
     const EditorJS = (await import('@editorjs/editorjs')).default;
     // @ts-ignore
     const Header = (await import('@editorjs/header')).default;
     // @ts-ignore
     const List = (await import('@editorjs/list')).default;
     // @ts-ignore
     const Embed = (await import('@editorjs/embed')).default;
     // @ts-ignore
     const Table = (await import('@editorjs/table')).default;
     // @ts-ignore
     const Quote = (await import('@editorjs/quote')).default;
     // @ts-ignore
     const Marker = (await import('@editorjs/marker')).default;
     // @ts-ignore
     const Warning = (await import('@editorjs/warning')).default;
     // @ts-ignore
     const LinkTool = (await import('@editorjs/link')).default;
     // @ts-ignore
     const RawTool = (await import('@editorjs/raw')).default;
     // @ts-ignore
     const Delimiter = (await import('@editorjs/delimiter')).default;
     // @ts-ignore
     const InlineCode = (await import('@editorjs/inline-code')).default;
     // @ts-ignore
     const SimpleImage = (await import('@editorjs/simple-image')).default;
     // @ts-ignore
     const Checklist = (await import('@editorjs/checklist')).default;
     // @ts-ignore
     const WarningTool = (await import('@editorjs/warning')).default;
     // @ts-ignore
     const CodeBox = (await import('@bomdi/codebox')).default;


    if (!editorRef.current) {
        const editor = new EditorJS({
            holder: 'editorjs',
            onReady: () => {
                editorRef.current = editor;

            },
            placeholder: 'Type here to write your content...',
            inlineToolbar: true,
            data: initialData,
            tools: {
                header: {
                    class: Header,
                    config: {
                        placeholder: 'Enter a header',
                        levels: [1,2, 3, 4,5,6],
                        defaultLevel: 1
                    }
                },
                list: List,
                embed: Embed,
                table: Table,
                quote: Quote,
                marker: Marker,
                warning: Warning,
                code: {
                    class: CodeBox,
                    config: {
                        themeURL: 'https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/styles/dracula.min.css',
                        themeName: 'atom-one-dark',
                    },
                },
                linkTool: {
                    class: LinkTool,
                    config: {
                        endpoint: '/api/blog/link',
                    },
                },
                raw: RawTool,
                delimiter: Delimiter,
                inlineCode: InlineCode,
                simpleImage: SimpleImage,
                checklist: Checklist,
            },
        });

        editorRef.current = editor;
    }
};

useEffect(() => {
    if (typeof window !== 'undefined') {
        setIsMounted(true);
    }
}, []);

useEffect(() => {
    const init = async () => {
        await initializeEditor();
    };

    if (isMounted) {
        init();
        return () => {
            editorRef.current?.destroy();
            editorRef.current = null;
        };
    }
}, [isMounted]);

return (
    <div className='mt-4'>
        <div id="editorjs" className="prose max-w-full border rounded-sm py-10 px-10" />
    </div>
);

}

export default Editor; `

Aestheticsuraj234 avatar Aug 18 '24 06:08 Aestheticsuraj234

I ran into this issue. The reason it's rendering twice is because React runs lifecycle functions like useEffect twice when in Strict Mode (which is enabled by default in development environments)

This component only renders the editor once and only destroys it if it has the destroy function (which it will only have if it is fully initialized)

import { Box } from "@chakra-ui/react";
import { useEffect, useRef } from "react";
import EditorJS from "@editorjs/editorjs";
import colors from "tailwindcss/colors";


export default function MarkdownEditor() {
  const editorRef = useRef<HTMLDivElement>(null)
  const editorInstance = useRef<EditorJS | null>(null);

  useEffect(() => {
    if (!editorRef.current || editorInstance.current) {
      return
    }

    editorInstance.current = new EditorJS({
      holder: editorRef.current,
    })

    return () => {
      if (editorInstance.current?.destroy) {
        editorInstance.current.destroy()
      }
    }
  }, [editorRef.current]);

  return (
    <Box>
      <Box ref={ editorRef }></Box>
    </Box>
  )
}

ip10x avatar Aug 22 '24 15:08 ip10x