draftjs how to initiate an editor with content

Viewed 54822

Stumbled on this cool text editor, draft.js by Facebook. I tried to follow the example in Github, but I want to create an editor with content instead of an empty editor.

var EditorState = Draft.EditorState;

var RichEditor = React.createClass({
   getInitialState(){
      return {editorState: EditorState.createWithContent("Hello")}
      //the example use this code to createEmpty editor
     // return ({editorState: EditorState.createEmpty()})
   }
});

When I run it, it throws an error with the following message "Uncaught TypeError: contentState.getBlockMap is not a function".

9 Answers

When you need to initiate an editor with plain text.

Use EditorState.createWithContent and ContentState.createFromText methods. Working example - https://jsfiddle.net/levsha/3m5780jc/

constructor(props) {
  super(props);

  const initialContent = 'Some text';
  const editorState = EditorState.createWithContent(ContentState.createFromText(initialContent));

  this.state = {
    editorState
  };
}

When you need to initiate an editor with content from the html markup string.

Use convertFromHTML and ContentState.createFromBlockArray. Working example - https://jsfiddle.net/levsha/8aj4hjwh/

constructor(props) {
  super(props);

  const sampleMarkup = `
        <div>
        <h2>Title</h2>
        <i>some text</i>
      </div>
    `;

  const blocksFromHTML = convertFromHTML(sampleMarkup);
  const state = ContentState.createFromBlockArray(
    blocksFromHTML.contentBlocks,
    blocksFromHTML.entityMap
  );

  this.state = {
    editorState: EditorState.createWithContent(state),
  };
}

When you have an array of string and you want to initiate an editor with some of the default draft.js block types.

You can create array of ContentBlockss with constructor new ContentBlock(...), and pass it to ContentState.createFromBlockArray method. Working example with unordered-list-item - https://jsfiddle.net/levsha/uy04se6r/

constructor(props) {
  super(props);
  const input = ['foo', 'bar', 'baz'];

  const contentBlocksArray = input.map(word => {
    return new ContentBlock({
      key: genKey(),
      type: 'unordered-list-item',
      characterList: new List(Repeat(CharacterMetadata.create(), word.length)),
      text: word
    });
  });

  this.state = {
    editorState: EditorState.createWithContent(ContentState.createFromBlockArray(contentBlocksArray))
  };
}

When you need to initiate an editor with content from ContentState raw JS structure.

If you previously saved you content state to raw JS structure with convertToRaw (read this answer for details). You can initiate an editor with convertFromRaw method. Working example - https://jsfiddle.net/levsha/tutc419a/

constructor(props) {
  super(props);

  this.state = {
    editorState: EditorState.createWithContent(convertFromRaw(JSON.parse(editorStateAsJSON)))
  };
}

In simple, you can set raw HTML content to editor from the initial stage or using setState at any time as below.

editorState: EditorState.createWithContent(ContentState.createFromBlockArray(convertFromHTML('<b>Program</b>')))

Import the necessary components.

import { EditorState, ContentState, convertFromHTML } from 'draft-js'

I found this to be a clean way of doing things with rich functionality. You can add more plugins in the future, export your content as .md etc without changing the structure of your component much.

import Draft from 'draft-js';

import DraftPasteProcessor from 'draft-js/lib/DraftPasteProcessor';
const { EditorState, ContentState } = Draft;
import Editor from 'draft-js-plugins-editor';

import createRichButtonsPlugin from 'draft-js-richbuttons-plugin';
const richButtonsPlugin = createRichButtonsPlugin();

class DescriptionForm extends React.Component {

state = {
  editorState: this._getPlaceholder(),
}

_getPlaceholder() {
  const placeholder = 'Write something here';
  const contentHTML = DraftPasteProcessor.processHTML(placeholder);
  const state = ContentState.createFromBlockArray(contentHTML);
  return Draft.EditorState.createWithContent(state);
}

_onChange(editorState) {
  this.setState({
    editorState,
  });
}

render () {
    let { editorState } = this.state;
    return (
      <div>
          <Editor
            editorState={editorState}
            onChange={this._onChange.bind(this)}
            spellCheck={false}
            plugins={[richButtonsPlugin, videoPlugin]}
          />
      </div>
    );
  }
}

You can set the initial value to your edtitorState just by add the folwwling code if you want to set it with HTML format

this.state = {
  editorState: EditorState.createWithContent(
    ContentState.createFromBlockArray(
      convertFromHTML('<p>My initial content.</p>')
    )
  ),
}

for Nextjs

import React, { Component } from 'react';
import { EditorState, convertToRaw, ContentState, convertFromHTML } from 'draft- 
js';
import draftToHtml from 'draftjs-to-html';
import dynamic from 'next/dynamic';
import "react-draft-wysiwyg/dist/react-draft-wysiwyg.css";

const Editor = dynamic(
() => import('react-draft-wysiwyg').then(mod => mod.Editor),
{ ssr: false }
)

let htmlToDraft = null;
if (typeof window === 'object') {
htmlToDraft = require('html-to-draftjs').default;
}

export default class EditorConvertToHTML extends Component {
constructor(props) {
    super(props);
    this.state = {
        editorState: EditorState.createEmpty(),
        contentState: ""
     }
    }

 componentDidMount() {

    const html = '<p>Hey this <strong>editor</strong> rocks d</p>';
    const contentBlock = htmlToDraft(html);
    console.log(contentBlock)
     if (contentBlock) {
        const contentState = 
        ContentState.createFromBlockArray(contentBlock.contentBlocks);
        const editorState = EditorState.createWithContent(contentState);
        console.log(editorState)
        this.setState(
            {
                editorState: EditorState.createWithContent(
                    ContentState.createFromBlockArray(
                        convertFromHTML(html)
                    )
                )
            }
          )
         }
        } 

     onEditorStateChange = (editorState) => {
     this.setState({
        editorState,
      });
     };

    render() {
    const { editorState } = this.state;
    console.log(this.state.editorState.getCurrentContent())
    return (
        <div>
            <Editor
                editorState={editorState}
                wrapperClassName="demo-wrapper"
                editorClassName="demo-editor"
                onEditorStateChange={this.onEditorStateChange}
            />
            <textarea
                disabled
                value= 
      {draftToHtml(convertToRaw(editorState.getCurrentContent()))}
            />
         </div>
        );
      }
        }
Related