35

I'm trying to persist draft-js's EditorContent to database then read and recreate the EditorContent object again. But EditorContent.getPlainText() strips away rich text content. I don't know how else to do it.

How do I properly persist EditorContent?

Dulguun Otgon
  • 1,925
  • 1
  • 19
  • 38

6 Answers6

52

The getPlainText() method, as its name suggests, only returns the plain text without any rich formatting. You should use the convertToRaw() and convertFromRaw() functions to serialize and deserialize the contents of the editor.

You can import them this way if necessary: (assuming you are using ES6)

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

If you need to export HTML instead, see https://medium.com/@rajaraodv/how-draft-js-represents-rich-text-data-eeabb5f25cf2#9260 (not sure you can import the contents back from HTML, though)

Lukas Liesis
  • 24,652
  • 10
  • 111
  • 109
christophetd
  • 3,834
  • 20
  • 33
  • I need to persist that into database. How do I serialize and deserialize it? – Dulguun Otgon Apr 08 '16 at 12:57
  • I can just store the raw object into mongodb, neat. – Dulguun Otgon Apr 09 '16 at 14:18
  • 1
    Is it a good idea to store the whole json object into a database? Is there a more efficient way to store draft.js content in a sql database? – Alexander Scholz Jun 11 '16 at 22:15
  • 1
    In my opinion, storing it inside a [JSON MySQL field](https://dev.mysql.com/doc/refman/5.7/en/json.html) would make a lot of sense and be efficient. – christophetd Jun 16 '16 at 12:22
  • This works pretty easily for me using Meteor, React, and Mongo. But when I restore with convertFromRaw, the Editor exhibits weird behavior: the cursor always jumps to the beginning of the Editor content, every time I press a key, and no matter where the cursor actually is. In other words all I can do is append content to the front. Is there some other step I'm missing with import? – Dave Munger Aug 11 '17 at 22:24
  • @DaveMunger probably issue with your internal app's state. Such "bug" is often with React and other similar frameworks when state is reset on change or component is re-mounted. Would suggest to dig more into those things to find out. Yet your message is old, maybe someone else will benefit :) – Lukas Liesis Jun 09 '20 at 04:32
18

I've found that I must stringify and parse the RawContentState object when reading and saving to the database.

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

// the raw state, stringified
const rawDraftContentState = JSON.stringify( convertToRaw(this.state.editorState.getCurrentContent()) );
// convert the raw state back to a useable ContentState object
const contentState = convertFromRaw( JSON.parse( rawDraftContentState) );
sealocal
  • 10,897
  • 3
  • 37
  • 50
10

There are a bunch of useful answers here so I want to add this jsfiddle demo. It shows how it works in action. For saving and retrieving of the content of the editor, here local storage is used. But for database case, the basic principle the same.

In this demo, you can see simple editor component, when you click on SAVE RAW CONTENT TO LOCAL STORAGE, we save current editor content as a string to local storage. We use convertToRaw and JSON.stringify for it:

 saveRaw = () => {
  var contentRaw = convertToRaw(this.state.editorState.getCurrentContent());

  localStorage.setItem('draftRaw', JSON.stringify(contentRaw));
}

If after that you reload the page, your editor will be initialized with the content and styles what you save. Becouse of in constructor we read the appropriate local storage property, and with JSON.parse, convertFromRaw and createWithContent methods initialize editor with the previously stored content.

constructor(props) {
  super(props);

  let initialEditorState = null;
  const storeRaw = localStorage.getItem('draftRaw');

  if (storeRaw) {
    const rawContentFromStore = convertFromRaw(JSON.parse(storeRaw));
    initialEditorState = EditorState.createWithContent(rawContentFromStore);
  } else {
    initialEditorState = EditorState.createEmpty();
  }

  this.state = {
    editorState: initialEditorState
  };
}
Mikhail Shabrikov
  • 8,453
  • 1
  • 28
  • 35
  • I tried using this technique, but I'm having issues converting from raw back to ContentState. I used the following line of code to serialize an empty state: `JSON.stringify(convertToRaw(EditorState.createEmpty().getCurrentContent()))` When I try to recreate the state later: `EditorState.createWithContent(convertFromRaw(JSON.parse(serialized_state)))` I get the following error: `TypeError: blockMap.first(...).getKey is not a function`. Looking through the source code didn't really help much. Any advice would be appreciated. Thanks. – Tadej Gašparovič May 09 '18 at 19:50
3

Edit: This is not a good way. See accepted answer.

To persist

const contentStateJsObject = ContentState.toJS();
const contentStateJsonString = JSON.stringify(contentStateJS);

Now the content state can be persisted as JSON string.

To recreate ContentState

const jsObject = JSON.parse(jsonString);
const contentState = new ContentState(jsObject);
Dulguun Otgon
  • 1,925
  • 1
  • 19
  • 38
  • This isn't probably the best way. See accepted answer. – Dulguun Otgon Apr 09 '16 at 14:17
  • This produces huge amounts of text (JSON). The accepted answer only produces a fraction of that. – Sthe Jan 17 '17 at 13:10
  • this is not official api, wouldn't do this. it's begging for bugs after draft version updates. just use official methods https://draftjs.org/docs/api-reference-data-conversion `convertFromRaw` and `convertToRaw` – Lukas Liesis Jun 09 '20 at 04:34
1

If you're going to save the raw content to your db using an AWS Lambda, I recommend stringifying within your Lambda code so you can then escape the single quotes; Then store it:

const escapedValueToStore = JSON.stringify(contentStateObject).replace(/'/g, '\'\'');

It's a bit involved, but it's basically because you stringify your data object when sending to your Lambda (via API Gateway) using POST.

You then need to parse that object, which then returns your ContentState into an Object without escaping the single quotes. You do the above-mentioned code to escape the quotes.

When using the data client side, all you need to do is parse it again as you convert it from raw:

EditorState.createWithContent(convertFromRaw(JSON.parse(rawContentState))

EDIT

On second thought, I guess you can just stringify, and escape the content on the client-side as well

Bennybear
  • 335
  • 2
  • 13
0

I did it for draftjs with reactjs. If u are still facing this issue: You can see the solution in this video

Basically you have to convertToRaw, then JSON.stringify it. Then this can be sent to your backend as a string. To display it, make a GET request for that particular data, then JSON.parse it and then convertFromRaw. Pass this into another RichTextEditor as the editorState but set the readOnly={true}

jmonica9
  • 11
  • 2