Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

Editor.js is not ready because of Error: element with ID «editorjs» is missing. Pass correct holder's ID.

Abierto
#2,914 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
3/5
Tiempo estimado
1-2 días
Aptitud para principiantes
35/100
Tipo de issue
Error
Claridad
Necesita aclaración
Estado de actividad
Estancado
Stack tecnológico
next.js, typescript
Área
frontend

Línea de trabajo

Comienza con el componente MyTextEditor y su ciclo de vida de useEffect alrededor del holder de EditorJS editorjs-container, y después reproduce la navegación entre páginas en la configuración de Next.js mostrada. Comprueba cuándo se producen la inicialización y la destrucción con respecto al renderizado del holder; estará terminado cuando los cambios de página ya no produzcan el error missing-element, mientras el editor siga inicializándose y guardando el contenido.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

bug

Can anyone please share the workaround for this issue when changing page it is coming everytime.I tried creating a client Editor component,and did a dynamic nossr import in the page to be used but still facing the issue. I am using NextJS.


'use client'
import { EDITOR_JS_TOOLS } from '@/lib/editorConfig';
import { createClient } from '@/lib/supabase/client';
import { useEffect, useRef, useState } from 'react';
import { toast } from 'react-toastify';
import EditorJS, { OutputData } from '@editorjs/editorjs';

const INITIAL_DATA = {
    time: 1701368244004,
    blocks: [
        {
            "type": "header",
            "data": {
                "text": "5 🔑s to a longer life ",
                "level": 1
            }
        },
        {
            "id": "zbGZFPM-iI",
            "type": "paragraph",
            "data": {
                "text": "Hey. Meet the new Editor. On this page you can see it in action — try to edit this text. Source code of the page contains the example of connection and configuration."
            }
        },
        {
            "id": "qYIGsjS5rt",
            "type": "header",
            "data": {
                "text": "Key features",
                "level": 3
            }
        },
        {
            "id": "XV87kJS_H1",
            "type": "list",
            "data": {
                "style": "unordered",
                "items": [
                    "It is a block-styled editor",
                    "It returns clean data output in JSON",
                    "Designed to be extendable and pluggable with a simple API"
                ]
            }
        },
        {
            "id": "AOulAjL8XM",
            "type": "header",
            "data": {
                "text": "What does it mean «block-styled editor»",
                "level": 3
            }
        },
        {
            "id": "cyZjplMOZ0",
            "type": "paragraph",
            "data": {
                "text": "Workspace in classic editors is made of a single contenteditable element, used to create different HTML markups. Editor.js <mark class=\"cdx-marker\">workspace consists of separate Blocks: paragraphs, headings, images, lists, quotes, etc</mark>. Each of them is an independent contenteditable element (or more complex structure) provided by Plugin and united by Editor's Core."
            }
        },
        {
            "type": "delimiter",
            "data": {}
        },
    ],
    version: "2.30.8",
};

interface EditorProps {
    initialData?: OutputData;
    id: number;
}

interface EditorState {
    isLoading: boolean;
    isDirty: boolean;
}

const MyTextEditor: React.FC<EditorProps> = ({ initialData, id }) => {
    const editorInstance = useRef<EditorJS | null>(null);
    const [editorData, setEditorData] = useState(initialData);
    const [isReadOnly, setIsReadOnly] = useState(true);
    const [state, setState] = useState<EditorState>({
        isLoading: false,
        isDirty: false,
    });
    const saveTimeoutRef = useRef<NodeJS.Timeout | undefined>(undefined);

    const debouncedSave = (data: OutputData) => {
        if (saveTimeoutRef.current) {
            clearTimeout(saveTimeoutRef.current);
        }

        saveTimeoutRef.current = setTimeout(async () => {
            await handleSave(data, false);
        }, 5000);
    };

    useEffect(() => {
        initEditor();
        return () => {
            if (saveTimeoutRef.current) {
                clearTimeout(saveTimeoutRef.current);
            }
            if (editorInstance.current?.destroy) {
                editorInstance.current?.destroy();
                editorInstance.current = null;
            }
        };
    }, [editorData, isReadOnly]);

    const initEditor = () => {
        if (!editorInstance.current) {
            const editor = new EditorJS({
                holder: "editorjs-container",
                tools: EDITOR_JS_TOOLS,
                data: editorData || INITIAL_DATA,
                onReady: () => {
                    console.log("Editor.js is ready to work!");
                    editorInstance.current = editor;
                },
                onChange: async (api) => {
                    setState(prev => ({ ...prev, isDirty: true }));
                    const data = await api.saver.save();
                    debouncedSave(data);
                },
                placeholder: "Type '/' for commands",
                readOnly: isReadOnly,
            });
        }
    }

    const extractHeader = (data: OutputData) => {
        const firstBlock = data['blocks']?.[0];
        return firstBlock?.type === "header" ? firstBlock.data.text : null;
    };

    const handleSave = async (data?: OutputData, reinitialize: boolean = true) => {
        try {
            setState(prev => ({ ...prev, isLoading: true }));
            if (!data && editorInstance.current) {
                data = await editorInstance.current.save();
            }
            if (!data) return;
            // Only update editor data if we want to reinitialize
            if (reinitialize) {
                setEditorData(data);
            }

            const title = extractHeader(data) || `Note_${id}`;
            const supabase = createClient();
            const { error } = await supabase
                .from('notes')
                .update({ content: data, title: title })
                .eq('id', id);

            if (error) throw error;

            setState(prev => ({ ...prev, isDirty: false }));
            toast.success("Content saved successfully!");
        } catch (error) {
            console.error("Error updating content:", error);
            toast.error("Failed to save data!");
        } finally {
            setState(prev => ({ ...prev, isLoading: false }));
        }
    };

    const toggleReadOnly = async () => {
        if (editorInstance.current) {
            await editorInstance.current.readOnly.toggle();
            setIsReadOnly((prev) => !prev);
            console.log("Read-Only Mode:", !isReadOnly);
        }
    };

    return <div className="p-2">
        <div className="flex gap-2 mb-4">
            <button
                className={`px-4 py-2 rounded-md transition-colors ${isReadOnly ? 'bg-blue-500 hover:bg-blue-600' : 'bg-gray-500 hover:bg-gray-600'
                    } text-white disabled:opacity-50`}
                onClick={toggleReadOnly}
            >
                {isReadOnly ? "Edit" : "Cancel"}
            </button>
            <button
                className="px-4 py-2 rounded-md bg-green-500 hover:bg-green-600 text-white disabled:opacity-50"
                onClick={() => handleSave()}
                disabled={isReadOnly || !state.isDirty || state.isLoading}
            >
                {state.isLoading ? "Saving..." : "Save"}
            </button>
            {state.isDirty && !isReadOnly && (
                <p className="text-sm text-gray-500 mt-2">Unsaved changes</p>
            )}
        </div>
        <div className="rounded-md" id='editorjs-container' />
        {/* <Image src='https://cdn.pixabay.com/photo/2023/07/31/16/37/sugar-apple-8161386_1280.jpg' alt={''} width={500} height={50} className='overflow-clip rounded-md object-fit m-6' /> */}
    </div>
}

export default MyTextEditor



// This should prevent the page from jumping during autosave while still maintaining the saving functionality. The editor will maintain its cursor position and scroll position during autosave operations.
// 1. Added a `reinitialize` parameter to `handleSave` that controls whether we update the editor state
// 2. Modified `debouncedSave` to call `handleSave` with `reinitialize: false` to prevent editor reinitialization during autosave
// 3. Only update `editorData` state when `reinitialize` is true (which will be the case for manual saves)
Lenguaje dominante
TypeScript
Estrellas
32k
Forks
2.2k
Merge medio
2 d 1 h
PR fusionados (30 d)
1

Preparar el entorno

Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de codex-team/editor.js

Todos los issues de codex-team/editor.js

Issues similares

Más issues de TypeScript

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.