Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Issue] Updating Yoopta's content programatically #424

Open
1 task done
SimpleVictor opened this issue Dec 30, 2024 · 6 comments
Open
1 task done

[Issue] Updating Yoopta's content programatically #424

SimpleVictor opened this issue Dec 30, 2024 · 6 comments

Comments

@SimpleVictor
Copy link

SimpleVictor commented Dec 30, 2024

Has this bug been raised before?

  • I have checked "open" AND "closed" issues and this is not a duplicate

Description

Are we able to update the editor's content programmatically? Maybe it wasn't intended to be updated like this?

I have a hook below to update the content after 3 seconds. However the change does not take effect at all. Is this expected?

const MARKS = [Bold, Italic, CodeMark, Underline, Strike, Highlight];

export default function Editor() {
  const editor = useMemo(() => createYooptaEditor(), []);
  const [value, setValue] = useState<YooptaContentValue>();

  const onChange = (
    value: YooptaContentValue,
    options: YooptaOnChangeOptions
  ) => {
    setValue(value);
  };

  useEffect(() => {
    setTimeout(() => {
      setValue({
        '9d98408d-b990-4ffc-a1d7-387084291b00': {
          id: '9d98408d-b990-4ffc-a1d7-387084291b00',
          value: [
            {
              id: '0508777e-52a4-4168-87a0-bc7661e57aab',
              type: 'heading-one',
              children: [
                {
                  text: 'Header one',
                },
              ],
              props: {
                nodeType: 'block',
              },
            },
          ],
          type: 'HeadingOne',
          meta: {
            order: 0,
            depth: 0,
          },
        },
      });
    }, 3000);
  }, []);

  return (
    <div>
      <YooptaEditor
        editor={editor}
        placeholder="Type text.."
        plugins={plugins}
        value={value}
        onChange={onChange}
        tools={TOOLS}
        // here we go
        marks={MARKS}
      />
    </div>
  );
}

Screenshots

No response

Do you want to work on this issue?

No

@Darginec05
Copy link
Collaborator

@SimpleVictor you can. Just use editor.setEditorValue instead setValue

@SimpleVictor
Copy link
Author

@Darginec05 So I gave that a try and yes it works once but when I tried using it again then it wouldn't update. For example below I have a nested timeout

  useEffect(() => {
    setTimeout(() => {
      editor.setEditorValue(
        {
          '9d98408d-b990-4ffc-a1d7-387084291b00': {
            id: '9d98408d-b990-4ffc-a1d7-387084291b00',
            value: [
              {
                id: '0508777e-52a4-4168-87a0-bc7661e57aab',
                type: 'heading-one',
                children: [
                  {
                    text: 'Updates 1',
                  },
                ],
                props: {
                  nodeType: 'block',
                },
              },
            ],
            type: 'HeadingOne',
            meta: {
              order: 0,
              depth: 0,
            },
          },
        }
      )

      setTimeout(() => {
        editor.setEditorValue(
          {
            '9d98408d-b990-4ffc-a1d7-387084291b00': {
              id: '9d98408d-b990-4ffc-a1d7-387084291b00',
              value: [
                {
                  id: '0508777e-52a4-4168-87a0-bc7661e57aab',
                  type: 'heading-one',
                  children: [
                    {
                      text: 'Updates 2',
                    },
                  ],
                  props: {
                    nodeType: 'block',
                  },
                },
              ],
              type: 'HeadingOne',
              meta: {
                order: 0,
                depth: 0,
              },
            },
          }
        )
      }, 3000);
    }, 3000);
  }, []);

@SimpleVictor
Copy link
Author

@Darginec05 I've created a reproducible playground here (https://playcode.io/2208081)

I have a button that calls editor.setEditorValue and generate a random text everytime. It only works once and then it doesn't update the content anymore.

@SimpleVictor
Copy link
Author

Here is a temp solution for others. I essentially updated the ids defined in the value + forced a rerender with the setRandomIncrement hook

export function Editor() {
  const editor = useMemo(() => createYooptaEditor(), []);
  const [value, setValue] = useState(undefined);
  const [randomIncrement, setRandomIncrement] = useState(1);

  const buttonClicked = () => {
    const topId = uuidv4();
    const childId = uuidv4();
    setRandomIncrement(randomIncrement + 1);
    editor.setEditorValue({
      [topId]: {
        id: topId,
        value: [
          {
            id: childId,
            type: 'paragraph',
            children: [
              {
                text: Date.now().toString(),
              },
            ],
            props: {
              nodeType: 'block',
            },
          },
        ],
        type: 'Paragraph',
        meta: {
          order: 0,
          depth: 0,
        },
      },
    });
  }

  return (
    <div style={{ width: "100%", height: "100%" }}>
      <button onClick={buttonClicked}>Click me</button>
      <YooptaEditor
        editor={editor}
        plugins={plugins}
        value={value}
        tools={TOOLS}
        marks={MARKS}
      />
    </div>
  );
}

@Darginec05
Copy link
Collaborator

In general, the main thing is that the IDs of each block should be new with each content update. You can use this API:

const setContent = () => {
  // editor.withoutSavingHistory(() => {
  const timestamp = Date.now().toString();

  const blockId = generateId();
  const elementId = generateId();

  const blockData: YooptaBlockData = Blocks.buildBlockData({
    id: blockId,
    value: [
      {
        id: elementId,
        type: 'heading-one',
        children: [{ text: timestamp }],
        props: {
          nodeType: 'block',
        },
      },
    ],
  });

  editor.setEditorValue({ [blockId]: blockData });
  // });
};

@lukmandev
Copy link

Then what is the point of library yoopta/exports?
How can i update editor without setting blockId myself

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants