Editor.js is not ready because of Error: element with ID «editorjs» is missing. Pass correct holder's ID.
まだ誰も着手していません。
評価
- 難易度
- 3/5
- 見積もり時間
- 1〜2日
- 初心者へのやさしさ
- 35/100
- issue の種類
- バグ
- 明瞭さ
- 説明が足りない
- 活発さ
- 停滞
- 技術スタック
- next.js, typescript
- 領域
- frontend
調査の方向性
MyTextEditor コンポーネントと、EditorJS の holder editorjs-container 周辺における useEffect のライフサイクルから始め、次に示されている Next.js の構成でページ間のナビゲーションを再現します。holder がレンダリングされるタイミングに対して、初期化と破棄がいつ発生するかを確認します。ページを変更しても missing-element エラーが発生せず、エディターが引き続き初期化されてコンテンツを保存できれば完了です。
索引モデルが issue の本文から書いたものです。
説明
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)
- 主要言語
- TypeScript
- スター
- 32k
- フォーク
- 2.2k
- 平均マージ
- 2日 1時間
- マージ済み PR(30日)
- 1
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
codex-team/editor.js のほかの issue
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
codex-team/editor.js#3037 ·
-
Floating Promise Anti-Pattern & Premature Caret in Multi-Block Paste対応中かも @anshurajbisoyi98-ctrl が 15 日前に担当しました。 オープンbug good first issue
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
codex-team/editor.js#3032 · コメント 1 件 ·
-
Silent Data Loss & Broken Error Contract in Saver.save()対応中かも @Sion612 が 25 日前に担当しました。 オープンbug
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
codex-team/editor.js#3030 ·
-
Complete Omission of block.destroy() in Blocks Collection対応中かも @Minhal128 が 24 日前に担当しました。 オープンbug
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
codex-team/editor.js#3029 ·
-
Bug: Link cannot be removed対応中かも @prathmeshyelne が 131 日前に担当しました。 オープンbug
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
codex-team/editor.js#3005 · コメント 1 件 ·
codex-team/editor.js の issue をすべて見る
似ている issue
-
難易度 1/5 1時間未満 初心者へのやさしさ 65/100
521xueweihan/HelloGitHub#4025 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
voidzero-dev/void#478 ·
メンテナーはふだん 1 日以内に返信
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 69/100
Small-tailqwq/dsh-deep-whale#207 ·
メンテナーはふだん 1 日以内に返信
-
The inspector never shows the instances field, so scaling out is unreachable対応中かも @Mrkewl が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
xevrion/breakscale#96 ·
メンテナーはふだん 4 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
Flux159/mcp-server-kubernetes#384 ·