13

I'm using Draft.js to implement a text editor. I want to save the content of the editor to a DB and later retrieve it and inject it in an editor again, e.g. when revisiting the editor page.

First, these are the relevant imports

import { ContentState, EditorState, convertToRaw, convertFromRaw } from 'draft-js';

How I Save the Data to the DB (located in a parent Component)

saveBlogPostToStore(blogPost) {
    const JSBlogPost = { ...blogPost, content: convertToRaw(blogPost.content.getCurrentContent())};
    this.props.dispatch(blogActions.saveBlogPostToStore(JSBlogPost));
}

Now when I check the DB, I get the following Object:

[{"_id":null,"url":"2016-8-17-sample-title","title":"Sample Title","date":"2016-09-17T14:57:54.649Z","content":{"blocks":[{"key":"4ads4","text":"Sample Text Block","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[]}]},"author":"Lukas Gisder-Dubé","__v":0,"tags":[]}]

So far so good I guess, I tried some other stuff and the Object in the Database is definitely converted. For example, when I save the content without calling the convertToRaw()-method, there are a lot more fields.

Setting the Data as new EditorState

To retrieve the Data from the DB and set it as EditorState, I also tried a lot. The following is my best guess:

constructor(props) {
    super(props);
    const DBEditorState = this.props.blogPost.content;
    console.log(DBEditorState); // logs the same Object as above
    this.state = { ...this.props.blogPost, content: EditorState.createWithContent(
        convertFromRaw(DBEditorState)
    )};
}

When rendering the component i get the following error:

convertFromRawToDraftState.js:38 Uncaught TypeError: Cannot convert undefined or null to object

Any help is greatly appreciated!

gisderdube
  • 477
  • 1
  • 3
  • 16
  • What is convertFromRaw function doing? – Kafo Sep 17 '16 at 15:45
  • It converts the raw JSON data to a ContentState Object usable in EditorState. See http://facebook.github.io/draft-js/docs/api-reference-data-conversion.html#content – gisderdube Sep 17 '16 at 15:47
  • It seems that you are giving the function an undefined or null object. constructor is going to be run once when the component is mounted. Any passes of props to it after mounting won't hit he conversion again. The conversion should probably go to componentDidMount instead of constructor. – Kafo Sep 17 '16 at 15:50
  • Add some log and make sure the raw content in `convertFromRaw` is the same JSON string from `convertToRaw`. – Jiang YD Sep 18 '16 at 01:19
  • @HusseinAlkaf Thank you for your advice, unfortunately this didn't resolve the problem. Also, you don't have to set the content, depending on the props, in componentDidMount(). You can directly set it in the constructor. JiangYD: not really helpful. – gisderdube Sep 18 '16 at 13:23

1 Answers1

24

Seems that MongoDB/Mongoose didn't like the raw content from the ContentState. Converting the data to a String before sending it to the DB did the trick:

Saving the ContentState to the DB

    saveBlogPostToStore(blogPost) {
    const JSBlogPost = { ...blogPost, content: JSON.stringify(convertToRaw(blogPost.content.getCurrentContent()))};
    this.props.dispatch(blogActions.saveBlogPostToStore(JSBlogPost));
}

Using the data from the DB

constructor(props) {
    super(props);
    const DBEditorState = convertFromRaw(JSON.parse(this.props.blogPost.content));

    this.state = { ...this.props.blogPost, content: EditorState.createWithContent(
        DBEditorState
    )};
}
gisderdube
  • 477
  • 1
  • 3
  • 16
  • For me, the bit Mongo(ose) didn't like is the `entityMap: {}` of simple editorState's with no entities - the `entityMap` property just gets discarded. Storing in a Mixed type works provided you check and reinstate the entityMap if it is missing. Not sure there's much benefit to a Mixed type anyways, but figured I'd just leave this here ... – Stevie Sep 12 '17 at 16:33
  • Instead of checking, should set { minimize: false } in the schema so it doesn't get remove. This solved my problem. – Someone Special May 22 '20 at 04:37
  • Thanks, this worked for me too. Had to stringify and then parse it for it to work. Took so long until I ran into this answer – cherucole Oct 09 '20 at 08:05