Sunday 30 August 2020

DraftJs: Replace an entity using its entity key

I'm creating a rich text editor using draftjs and can't find any ressources to help me in my problem.

Please first have look to the codesandbox.

You can see a text that contains a link (testtest in red). If you click on it you will see some infos of the link in the table:

| 🔗 link src         | http://localhost:8080/testtest |
| 📝 link text        | testtest                       |
| 🔑 link Entity key  | ab5a7c6d...                    |

I get the current link key (🔑) thanks to my getCurrentLinkKey helper:

const getCurrentLinkKey = (
  editorState: EditorState,
  contentState?: ContentState
): string => {
  if (contentState === undefined) {
    contentState = editorState.getCurrentContent();
  }

  const startKey = editorState.getSelection().getStartKey();
  const startOffset = editorState.getSelection().getStartOffset();
  const blockWithLinkAtBeginning = contentState.getBlockForKey(startKey);

  return blockWithLinkAtBeginning.getEntityAt(startOffset);
};

Then with this key I can get the link Entity using getCurrentLinkEntity helper:

const getCurrentLinkEntity = (
  editorState: EditorState
): EntityInstance | null => {
  const contentState = editorState.getCurrentContent();
  const linkKey = getCurrentLinkKey(editorState, contentState);

  if (linkKey) {
    return contentState.getEntity(linkKey);
  }

  return null;
};

Using the link Entity I can finally get the src and text value:

getCurrentLinkEntity(editorState).getData().url   // 🔗
getCurrentLinkEntity(editorState).getData().text  // 📝

You can see at the bottom a button Insert link. If you select the entire link testtest and click on this button, the link will be replaced.

This feature is handled by the insertLink helper:

const insertLink = (
  link: string,
  text: string,
  editorState: EditorState,
  setEditorState: (editorState: EditorState) => void
): void => {
  const contentStateWithEntity = editorState
    .getCurrentContent()
    .createEntity("LINK", "MUTABLE", { url: link, text });

  const entityKey = contentStateWithEntity.getLastCreatedEntityKey();

  const contentState = Modifier.replaceText(
    editorState.getCurrentContent(),
    editorState.getSelection(),
    text,
    editorState.getCurrentInlineStyle(),
    entityKey
  );

  const newEditorState = EditorState.set(editorState, {
    currentContent: contentStateWithEntity
  });
  const newEditorStateWithLink = RichUtils.toggleLink(
    newEditorState,
    newEditorState.getSelection(),
    entityKey
  );

  setEditorState(
    EditorState.push(newEditorStateWithLink, contentState, "insert-characters")
  );
};

But this function will just replace your selected text by the google link. What I want is, if you are on a link and click the button, then the entire link should be updated. So I created the replaceLink helper:

const replaceLink = (
  link: string,
  text: string,
  editorState: EditorState,
  setEditorState: (editorState: EditorState) => void
): void => {
  const contentStateWithEntity = editorState
    .getCurrentContent()
    .createEntity("LINK", "MUTABLE", { url: link, text });

  const entityKey = contentStateWithEntity.getLastCreatedEntityKey();

  const newEditorState = EditorState.set(editorState, {
    currentContent: contentStateWithEntity
  });

  const contentState = newEditorState
    .getCurrentContent()
    .replaceEntityData(getCurrentLinkKey(editorState), { entityKey });

  const newEditorStateWithLink = RichUtils.toggleLink(
    newEditorState,
    newEditorState.getSelection(),
    entityKey
  );

  setEditorState(
    EditorState.push(newEditorStateWithLink, contentState, "insert-characters")
  );
};

But sadly, if I click on the Replace link button (that trigger replaceLink helper), the link is not updated but src and text are empty:

| 🔗 link src         |             |
| 📝 link text        |             |
| 🔑 link Entity key  | a1e34047... |

So as someone an idea how I can replace the link Entity using it's entity key?



from DraftJs: Replace an entity using its entity key

No comments:

Post a Comment