Skip to content
This repository has been archived by the owner on Feb 6, 2023. It is now read-only.

How would I initialize an Editor with some text? #284

Closed
hyperh opened this issue Apr 9, 2016 · 21 comments
Closed

How would I initialize an Editor with some text? #284

hyperh opened this issue Apr 9, 2016 · 21 comments

Comments

@hyperh
Copy link

hyperh commented Apr 9, 2016

I want to initialize an Editor with some default text, some with styling (such as bold, H1, H2, etc...) and some plain text. Not sure how to do this. The convertFromRaw requires an array of ContentBlocks, but I'm not sure how to generate the keys for them. Or is there a better way, such as just importing from some html?

@brookslyrette
Copy link
Contributor

There are functions to convert from HTML see #236

I've used this with success in a previous project.

import React, { PropTypes } from 'react';
import { ContentState, Editor, EditorState, RichUtils, convertToRaw } from 'draft-js';
import DraftPasteProcessor from 'draft-js/lib/DraftPasteProcessor';

export default class MyEditor extends React.Component {

    constructor(props) {
        super(props);
        let editorState;
        if (this.props.content.trim() !== "'') {
            const processedHTML = DraftPasteProcessor.processHTML(this.props.content);
            const contentState = ContentState.createFromBlockArray(processedHTML);
            //move focus to the end. 
            editorState = EditorState.createWithContent(contentState);
            editorState = EditorState.moveFocusToEnd(editorState);
        }
        else {
            editorState = EditorState.createEmpty();
        }

        this.state = {
            editorState: editorState
        };
    }
}

@hyperh
Copy link
Author

hyperh commented Apr 9, 2016

What does this.props.content look like? Is it just a string like so '<div>My content</div>'

Edit: Actually I see the tests done on it in https://github.com/facebook/draft-js/blob/67c5e69499e3b0c149ce83b004872afdf4180463/src/model/paste/__tests__/DraftPasteProcessor-test.js.

Thanks for the helpful info! Hopefully there's more complete documentation on all of Draft's libraries soon.

@hyperh hyperh closed this as completed Apr 9, 2016
@sungwoncho
Copy link

sungwoncho commented Aug 29, 2016

@brookslyrette Your solution works great on the client side. However, when rendering on the server side, I get an error that document is not defined:

[1] ReferenceError: document is not defined
[1]     at getSafeBodyFromHTML (/Users/mikecho/dev/go/src/remotebase/node_modules/draft-js/lib/getSafeBodyFromHTML.js:27:19)
[1]     at getChunkForHTML (/Users/mikecho/dev/go/src/remotebase/node_modules/draft-js/lib/convertFromHTMLToContentBlocks.js:366:18)
[1]     at convertFromHTMLtoContentBlocks (/Users/mikecho/dev/go/src/remotebase/node_modules/draft-js/lib/convertFromHTMLToContentBlocks.js:422:15)
[1]     at Object.processHTML (/Users/mikecho/dev/go/src/remotebase/node_modules/draft-js/lib/DraftPasteProcessor.js:31:12)
[1]     at new RichEditor (/Users/mikecho/dev/go/src/remotebase/src/components/admin/rich_editor.jsx:13:49)
[1]     at [object Object].ReactCompositeComponentMixin._constructComponentWithoutOwner (/Users/mikecho/dev/go/src/remotebase/node_modules/react/lib/ReactCompositeComponent.js:296:27)
[1]     at [object Object].ReactCompositeComponentMixin._constructComponent (/Users/mikecho/dev/go/src/remotebase/node_modules/react/lib/ReactCompositeComponent.js:278:21)
[1]     at [object Object].ReactCompositeComponentMixin.mountComponent (/Users/mikecho/dev/go/src/remotebase/node_modules/react/lib/ReactCompositeComponent.js:190:21)
[1]     at Object.ReactReconciler.mountComponent (/Users/mikecho/dev/go/src/remotebase/node_modules/react/lib/ReactReconciler.js:47:35)
[1]     at ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (/Users/mikecho/dev/go/src/remotebase/node_modules/react/lib/ReactMultiChild.js:240:44)

using draft-js 0.8.1.

Any suggestions?

@4nte
Copy link

4nte commented Oct 13, 2016

@sungwoncho Have you found a solution? I'm having the same issue
(Anyone?)

@sungwoncho
Copy link

@theguxi I have not found a solution yet.

@mzbac
Copy link
Contributor

mzbac commented Oct 15, 2016

type some text and apply your desired styles then get contentState from editor, convertToRaw it to rawContent. then do something like:

contentState = {
                  entityMap: {},
                  blocks: [{
                    key: '18ql9',
                    text: 'your words',
                    type: 'unstyled',
                    depth: 0,
                    inlineStyleRanges: [],
                    entityRanges: [],
                  }],
                };
EditorState.createWithContent(convertFromRaw(contentState))

@ducnvhn
Copy link

ducnvhn commented Nov 1, 2016

Have same issue while trying ton render on server side using convertToHTML function. Any update on this issue please.

@davidchang
Copy link
Contributor

related: #385

@davidchang
Copy link
Contributor

has this been confirmed for v0.9.1?

@jide
Copy link

jide commented Jan 17, 2017

Here is a complete boilerplate I ended up with, allowing passing initial and getting html content. You need to install draft-convert. It uses react-draft-wysiwyg, but should work the same with vanilla draft-js.

import React, { Component, PropTypes } from 'react';
import { convertFromHTML, EditorState, ContentState } from 'draft-js';
import { convertToHTML } from 'draft-convert';
import { Editor } from 'react-draft-wysiwyg';

export default class RichTextField extends Component {
  constructor(props) {
    super(props);

    let editorState;

    if (props.content) {
      const blocksFromHTML = convertFromHTML(props.content);
      const contentState = ContentState.createFromBlockArray(blocksFromHTML);
      editorState = EditorState.createWithContent(contentState);
    }
    else {
      editorState = EditorState.createEmpty();
    }

    this.state = { editorState };
  }

  handleChange = editorState => {
    const content = convertToHTML(editorState.getCurrentContent());
    console.log(content);
  }

  render() {
    return (
      <Editor
        defaultEditorState={ this.state.editorState }
        onEditorStateChange={ this.handleChange }
      />
    );
  }
}

RichTextField.propTypes = {
  content: PropTypes.string
};

@ghost
Copy link

ghost commented Feb 6, 2017

Thanks a lot for the boilerpalte @jide
How do you get the content to remain in the editor after a refresh?

The content is sucessfully inserted in the DB, I get it back in the console log, but don't know how to keep it in the Editor...

handleChange = editorState => {
  const content = convertToHTML(editorState.getCurrentContent());
  Meteor.call('bins.update', this.props.bin, content);
  console.log(this.props.bin.content);
}

@jide
Copy link

jide commented Feb 6, 2017

@astenmies I ended up doing something like this, I stripped down to the minimum from my needs, you may need to adapt :

import React, { Component, PropTypes } from 'react';
import { convertFromHTML, EditorState, ContentState } from 'draft-js';
import { convertToHTML } from 'draft-convert';
import { Editor } from 'react-draft-wysiwyg';
import debounce from 'lodash.debounce';

export default class RichTextField extends Component {
  constructor(props) {
    super(props);

    this.state = {
      editorState: this.getInitialStateFromHTMLValue(props.content)
    };
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.content !== convertToHTML(this.state.editorState.getCurrentContent())) {
      this.setState({
        editorState: this.getUpdatedStateFromHTMLValue(nextProps.content)
      });
    }
  }

  componentWillUnmount() {
    this.unmounted = true;
  }

  getInitialStateFromHTMLValue = value => {
    let editorState;

    if (value) {
      const blocksFromHTML = convertFromHTML(value);
      const contentState = ContentState.createFromBlockArray(blocksFromHTML);
      editorState = EditorState.createWithContent(contentState);
      editorState = EditorState.set(editorState);
    }
    else {
      editorState = EditorState.createEmpty();
    }

    return editorState;
  }

  getUpdatedStateFromHTMLValue = value => {
    const { editorState } = this.state;
    const blocksFromHTML = convertFromHTML(value);
    const nextContentState = ContentState.createFromBlockArray(blocksFromHTML);

    return EditorState.push(editorState, nextContentState);
  }

  debouncedOnChange = debounce(this.props.onChange, 100)

  handleChange = editorState => {
    const prevValue = convertToHTML(this.state.editorState.getCurrentContent());
    const nextValue = convertToHTML(editorState.getCurrentContent());

    if (!this.unmounted) {
      this.setState({ editorState }, () => {
        if (prevValue !== nextValue) {
          this.debouncedOnChange(nextValue);
        }
      });
    }
  }

  render() {
    return (
      <Editor
        editorState={ this.state.editorState }
        onEditorStateChange={ this.handleChange }
      />
    );
  }
}

RichTextField.propTypes = {
  content: PropTypes.string,
  onChange: PropTypes.func.isRequired
};

RichTextField.defaultProps = {
  onChange: () => {}
};

@ghost
Copy link

ghost commented Feb 6, 2017

Nice @jide. This draft-js is almost the last step of my project and I'm really stuck with this.
By chance do you have any idea why I'm getting a Cannot read property 'trim' of undefined in the inspector, when doing this ... ?

if (!this.unmounted) {
  this.setState({ editorState }, () => {
    if (prevValue !== nextValue) {
      this.debouncedOnChange(nextValue);
    }
  });
  Meteor.call('bins.update', this.props.bin, nextValue);
}

@jide
Copy link

jide commented Feb 7, 2017

In my example the prop is called "content", whereas it seems you use a "bin" prop.

@nnurmano
Copy link

@jide, I am trying to use the boilerplate you provided, but it says this.props.onChange is not available. Should this function be passed from the parent component?

@nnurmano
Copy link

Additionally, on this line editorState = EditorState.set(editorState); I have the following error
"TypeError: Cannot read property 'decorator' of undefined"

@abbycoco
Copy link

abbycoco commented Dec 1, 2017

@brookslyrette If the html contain the img, it just find a photo icon , the img can not show normally. Do you have the same problem? or Do you have a solution?

@raheemazeezabiodun
Copy link

@brookslyrette thanks for the explanation, it worked in my case

@brookslyrette
Copy link
Contributor

@abbycoco Image support was not a required use-case for the work I did. We never tested it.

@shivarajalagond
Copy link

@abbycoco : Did you find the solution? I had the same problem, found that the problem was with image URL.

@GodAlmighty990
Copy link

type some text and apply your desired styles then get contentState from editor, convertToRaw it to rawContent. then do something like:

contentState = {
                  entityMap: {},
                  blocks: [{
                    key: '18ql9',
                    text: 'your words',
                    type: 'unstyled',
                    depth: 0,
                    inlineStyleRanges: [],
                    entityRanges: [],
                  }],
                };
EditorState.createWithContent(convertFromRaw(contentState))

This solution helped me with rendering multiple draft.js editors, some with TEXT ONLY content and some with SUGGESTIONS AND EMOJI. In my case I was rendering just fine with suggestions or emojis, but with only plain text in the editor I was getting an error Here was my solution below for rendering the draftjs in a table

const bodyFormatter = (rowData) => {
      const { _id, body } = rowData.row.original
      let editorState
      let contentState
      console.log(body)
      if(!body.entityMap) {
        contentState = { entityMap: {},
                          blocks: body.blocks}
        editorState = EditorState.createWithContent(convertFromRaw(contentState))
      } else { 
        console.log(body)
        const decorators = _.flattenDeep(plugins.map((plugin) => plugin.decorators));
        const decorator = new CompositeDecorator(decorators.filter((decorator, index) => index !== 1) );
        editorState = EditorState.createWithContent(
        convertFromRaw(body), decorator)
        console.log(editorState)
  }```

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests