react-draft-wysiwyg: Unknown DraftEntity key: null.

Error: image

Code to run:

        const contentBlock = htmlToDraft(sanitizeHtml(this.wysiwygHtml.value, sanitizeRules));
        const contentState = ContentState.createFromBlockArray(contentBlock.contentBlocks);
        const newEditorState = EditorState.createWithContent(contentState);
        this.onEditorStateChange(newEditorState);

Code to paste:

<a href="https://test.com" target="_blank" data-saferedirecturl="https://www.test.com/url?hl=ru&amp;q=https://test.com&amp;source=gmail&amp;ust=1518687009434000&amp;usg=AFQjCNGJCuM_hG6wsHlvqVTpepzndFgVkQ"><img src="https://proxy/28oL4gKFefkX8wOuCE5zIS5UPzeCfGKO-3mjWWCNk_HZOIIhR9Kxyx9sKG2nNKU_SWOVY_dk_lVVJKxv-P7pRe__6VurG3wi6kOwiHXAERe7RjM=s0-d-e1-ft#https://test.com/images/signatures/new/ira.jpg" alt="" class="CToWUd"></a>

Versions:

    "react-draft-wysiwyg": "^1.12.7",
    "draft-js": "^0.10.5",
    "draftjs-to-html": "^0.8.2",
    "html-to-draftjs": "^1.1.2"

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Comments: 46 (7 by maintainers)

Most upvoted comments

This is a very real problem and I got a good reproduction case:

  1. Go to https://jpuri.github.io/react-draft-wysiwyg/#/demo
  2. Insert an image in the first editor
  3. Go up to place the caret above the image and press delete to remove the very first <p>
  4. You should have:
<img src="image.jpg" alt="undefined" style="float:none;height: auto;width: auto"/>
<p></p>

in the html preview.

First Problem: The image is still in the generated html but not in the editor anymore.

Second problem: If you initialize an editor with this HTML (which is generated by draftjs-to-html) you get the above crash: Invariant Violation: Unknown DraftEntity key: null.

Edit: Here’s the broken state json dump:

> JSON.stringify(editorState.getCurrentContent().toJSON(), null, 2)

{
  "entityMap": {},
  "blockMap": {
    "c9cv2": {
      "key": "c9cv2",
      "type": "atomic",
      "text": "",
      "characterList": [],
      "depth": 0,
      "data": {}
    },
    "2gj8i": {
      "key": "2gj8i",
      "type": "unstyled",
      "text": " ",
      "characterList": [
        {
          "style": [],
          "entity": "1"
        }
      ],
      "depth": 0,
      "data": {}
    }
  },
  "selectionBefore": {
    "anchorKey": "c9cv2",
    "anchorOffset": 0,
    "focusKey": "c9cv2",
    "focusOffset": 0,
    "isBackward": false,
    "hasFocus": false
  },
  "selectionAfter": {
    "anchorKey": "c9cv2",
    "anchorOffset": 0,
    "focusKey": "c9cv2",
    "focusOffset": 0,
    "isBackward": false,
    "hasFocus": false
  }
}

The first block (c9cv2) crash because block.getEntityAt(0) is null here: https://github.com/jpuri/react-draft-wysiwyg/blob/f0da14fe8d082ee078da1c2eceac3789d400db26/src/renderer/index.js#L11

I solved this error. I do a function which one add an image into editor, it’s mean I have to get the link of image then add it to img tag of HTML, problem is here. Add it into <p><img src="your_image_link" ></img></p> before parse it into editor again. The p tag is required in editor.

after I post an image in editor, I try to enter somthing and got this error;

I resolved this problem by changing the version of draft-js to 0.10.*

This bug happened when the incoming HTML was missing a prefixed <p></p> tag. When prepending a <p></p> to the incoming html it fixed the error. This is just a temporary fix, but might provide clues to the larger problem. Sometimes when trying to delete an image, the <p></p> tags are deleted, but the editor shows that the image has been deleted.

[missing p tags here. Shows that image is gone in editor preview]
<img src="http://somerandomurl.com" alt="asdf" style="float:none;height: auto;width: auto"/>
<p></p>

If this state gets saved, then it’ll error out when you reload.

Also, make sure if you going and pulling prefetch data then it must surround by p tag or something. I don’t know exactly but for my case, it’s working

editorState: EditorState.createWithContent(
                  ContentState.createFromBlockArray(
                    htmlToDraft("<p>"+MYVARIABLE+"</p>")
                  )
                ),

or editorState: EditorState.createWithContent( ContentState.createFromBlockArray( htmlToDraft("<p>Initial content</p>") ) ),

I switched to tinymce self-hosted, at last.

I solved the issue using convertFromHTML from draft-js. My problem was figure HTML tag in the content.

const { contentBlocks, entityMap } = convertFromHTML(this.getInputValue() || '')
const contentState = ContentState.createFromBlockArray(contentBlocks, entityMap)
.
.
.
<Editor {...otherProps} editorState={EditorState.createWithContent(contentState)} />

Ok this code seems to work, I added a couple packages you can see from imports:

import {EditorState, convertToRaw, Modifier} from "draft-js";
import { stateFromHTML } from "draft-js-import-html";
import sanitizeHtml from 'sanitize-html';

const getSelectedBlock = (editorState:EditorState) => {
    const selection = editorState.getSelection();
    const contentState = editorState.getCurrentContent();
    const blockStartKey = selection.getStartKey();
    
    return contentState.getBlockMap().get(blockStartKey);
  }

  const handlePastedText = (
    text: string,
    html: string,
    editorState: EditorState,
    onChange: (editorState: EditorState) => void
  ) => {
    try {

   
    const selectedBlock = getSelectedBlock(editorState);
    if (selectedBlock && selectedBlock.getType() === "code") {
      const contentState = Modifier.replaceText(
        editorState.getCurrentContent(),
        editorState.getSelection(),
        text,
        editorState.getCurrentInlineStyle()
      );
      onChange(
        EditorState.push(editorState, contentState, "insert-characters")
      );
      return true;
    } else if (html) {
      // const fixedHTML = html.replace(/<img.*>/gi, "\n");
      let fixedHTML = sanitizeHtml(html)
        .replace(/(<\/?)img((?:\s+.*?)?>)/g, "")
        .replace(/(<\/?)figure((?:\s+.*?)?>)/g, "");
      const blockMap = stateFromHTML(fixedHTML).getBlockMap();
      const newState = Modifier.replaceWithFragment(
        editorState.getCurrentContent(),
        editorState.getSelection(),
        blockMap
      );
      onChange(EditorState.push(editorState, newState, "insert-fragment"));
      return true;
    }
    return false;
 }catch(error) {
      console.error(error);
      return false;
    }
  };

This could be because some text uses the figure tag, but draft reserves this tag. You could bypass the “handlePastedText” with your own function like so:

Just pass the parameter handlePastedText={HandlePastedText} in the Editor and import the function below as HandlePastedText.

/**
 *
 * @param text text on clipboard
 * @param html html on clipboard (no IE11 support)
 * @param editorState
 * @param onChange
 * @returns {boolean} true states to editor paste is handled, false will continue with standard paste behavior of editor
 */
const handlePastedText = (text, html, editorState, onChange) => {
	const selectedBlock = getSelectedBlock(editorState);
	if (selectedBlock && selectedBlock.type === 'code') {
		const contentState = Modifier.replaceText(
				editorState.getCurrentContent(),
				editorState.getSelection(),
				text,
				editorState.getCurrentInlineStyle()
		);
		onChange(EditorState.push(editorState, contentState, 'insert-fragment'));
		return true;
	} else if (html) {
		//Figure can be under the copied html, but is reserved in the editor. Since figure contains an img tag, simply strip figure.
		if (html.indexOf('<figure') != -1) {
			html = html.replace(/(<\/?)figure((?:\s+.*?)?>)/g, '');
		}
		const contentBlock = htmlToDraft(html);
		let contentState = editorState.getCurrentContent();
		contentBlock.entityMap.forEach((value, key) => {
			contentState = contentState.mergeEntityData(key, value);
		});
		contentState = Modifier.replaceWithFragment(
				contentState,
				editorState.getSelection(),
				new List(contentBlock.contentBlocks)
		);
		onChange(EditorState.push(editorState, contentState, 'insert-fragment'));
		return true;
	}
	return false;
};
export default handlePastedText;

My final solution is replace this package for the React Quill package, much better for working with html tags

I have fixed similar issue on Firefox by updating draft js "draft-js": "0.11.0-beta2"

and set global config:

window.__DRAFT_GKX = {
     draft_killswitch_allow_nontextnodes: true,
}

For Me, The reason for the problem is the type was “atomic” but entityRanges is empty

 {
      "key": "as6q7",
      "text": "",
      "type": "atomic",
      "depth": 0,
      "inlineStyleRanges": [],
      "entityRanges": [],
      "data": {}
    }

@marcaaron, can you plz share exactly when you get error. You can save editor content as JSON check example 2. Uncontrolled editor component with conversion of content from and to JSON (RawDraftContentState) Here: https://jpuri.github.io/react-draft-wysiwyg/#/demo

In fact that is the recommended way to save editor content.

I has same problem with inserting Image from clipboard. And I used this code for updating editorState return AtomicBlockUtils.insertAtomicBlock( newEditorState, entityKey, '' );
I tried to solve this problem, and change ‘’ for ’ ’ (with space) helped me 😕 it’s sound crazy, but it works for me)

My solution was also deleting the figure tag: htmlValue.replace(/(<\/?)figure((?:\s+.*?)?>)/g, '')

The whole code in case is useful for anyone:

const { contentBlocks, entityMap } = htmlToDraft(
  htmlValue.replace(/(<\/?)figure((?:\s+.*?)?>)/g, '') // Delete <figure> tag that causes DraftJS error
);
const contentState = ContentState.createFromBlockArray(
  contentBlocks,
  entityMap
);
setEditorState(EditorState.createWithContent(contentState));

It may be problem of DraftJS itself? I got similar problem on Firefox since I have update DraftJS >= 0.10.1. On Chrome it works ok

I have the same problem. When I using <ifream> tag and delete it, sometimes it will be deleted in views, but actually it not be deleted in data. And then, if I ender Editor again, I get this ERROR.

Is there a solution to this yet?

The app I’m building saves exported html to a database and allows users to then come back at a later date and import/edit the content with the editor. But does not work if images are added. Is there some workaround for this? Maybe stringify the data, save it to the database, and recreate the editorState with images? I tried with editorState… but this does not work. Any ideas?

@jpuri Error, when i running this code

        const contentBlock = htmlToDraft(sanitizeHtml(this.wysiwygHtml.value, sanitizeRules));
        const contentState = ContentState.createFromBlockArray(contentBlock.contentBlocks);
        const newEditorState = EditorState.createWithContent(contentState);
        this.onEditorStateChange(newEditorState);