Maybe is a basic question (actually I guess is not related with your current draft based editor), but I don't get at all how draftjs works. I've been trying to load some html using the demo as example and so far I've tried something like this:
import React from 'react'
import { Modal } from 'react-bootstrap'
import { Editor } from 'react-draft-wysiwyg';
import draftToHtml from 'draftjs-to-html';
import { convertFromHTML, ContentState, convertToRaw } from 'draft-js';
export default class EditDescriptionModal extends React.Component {
constructor(props) {
super(props);
this.state = {editorContent: this._getInitialHTML()};
}
_getInitialHTML() {
const contentBlocks = convertFromHTML('<p>Hello world</p>');
const contentState = ContentState.createFromBlockArray(contentBlocks);
return convertToRaw(contentState);
}
onEditorChange(editorContent) {
console.log(draftToHtml(editorContent))
this.setState({ editorContent });
};
render(){
const { editorContent } = this.state;
return(
<Modal show={this.props.showModal} onHide={this.props.onClose}
bsSize="large" >
<form className="form-horizontal" >
<Modal.Header closeButton>
<Modal.Title>Edit description</Modal.Title>
</Modal.Header>
<Modal.Body>
<div className="demo-editorSection">
<div className="demo-editorWrapper">
<Editor
rawContentState={editorContent}
toolbarClassName="demo-toolbar"
wrapperClassName="demo-wrapper"
editorClassName="demo-editor"
onChange={this.onEditorChange.bind(this)}
toolbarAlwaysVisible
/>
</div>
</div>
</Modal.Body>
<Modal.Footer>
<button type="submit" className="btn btn-info">Submit</button>
<button type="button" className="btn"
onClick={this.props.onClose}>Close</button>
</Modal.Footer>
</form>
</Modal>
)
}
}
So is supposed it should display that <p>Hello world</p> as initial editor content passing to the rawContentState of the Editor component, but I think I'm wrong.
In any case, if I add some text to the editor, is correctly converted to HTML in the onEditorChange function. What I'm doing wrong here?.
BTW, kudos for the great work done
Hi @alagos ,
Check similar example here: https://github.com/jpuri/react-draft-wysiwyg/blob/master/docs/src/components/Demo/index.js#L140
@jpuri yes, actually, that's the specific example I'm basing of. Instead of using sampleEditorContent to load the content in rawContentState={sampleEditorContent} I loaded it from the state and I almost copy/pasted the content from https://github.com/jpuri/react-draft-wysiwyg/blob/master/docs/src/util/sampleEditorContent.js to my _getInitialHTML function to load the initial data for the state, but is not working.
Not sure if has something to do, but I'm using 0.2.1 version.
ok try to do a console log and check whats coming in editorContent after this line const { editorContent } = this.state;.
That's the result with console.log(JSON.stringify(editorContent));:
{
"entityMap": {},
"blocks": [
{
"key": "1n9j8",
"text": "Hello world",
"type": "unstyled",
"depth": 0,
"inlineStyleRanges": [],
"entityRanges": [],
"data": {}
}
]
}
and after I click the editor to write something and render is reevaluated, the result is:
{
"entityMap": {},
"blocks": [
{
"key": "a5b87",
"text": "",
"type": "unstyled",
"depth": 0,
"inlineStyleRanges": [],
"entityRanges": [],
"data": {}
}
]
}
Its looks like editor is re-mounting in each render - which I do not expect to be the case, it may be an issue with Modal component.
Ideally editor should have been initialized only once but apparently its content are reset second time also.
I ran into the same problem where my editorContents was null the first time I rendered, then was populated on a second render. A quick and dirty fix of not rendering until I know the data is there worked for me.
` render() {
const { editorContents } = this.state;
if (!editorContents) {
return <div />;
}
return (
<div>
<div className="demo-label">
Editor with output generated in HTML.
</div>
<div className="demo-editorSection">
<Editor
toolbarClassName="demo-toolbar"
wrapperClassName="demo-wrapper"
editorClassName="demo-editor"
rawContentState={editorContents}
onChange={this.onEditorChange.bind(this)}
toolbar={{
options: ['inline', 'blockType', 'textAlign', 'link', 'remove', 'history'],
inline: {
options: ['bold', 'italic', 'underline', 'strikethrough'],
},
}}
/>
</div>
</div>
);
}`
@ytwater: you can also check new contentState property (detailed in docs) it can be used not only for initializing but also changing editor content.
@alagos: is your issue resolved, can I do something more to help it ?
@jpuri at the end I moved to another editor as I couldn't figure out what was going on, sorry about that. Anyway thanks for the help :)
same issue here using react-bootstrap modal
For ones who are wondering how to initialize it with HTML content instead of empty here is the way you need to generate editorState with the content you have, to init editorState there is a function in draft-js EditorState component and I am using a converter draft-js-import-html which allows to generate contentState out of HTML content, see below
import {EditorState, ContentState, convertFromHTML, convertToRaw} from 'draft-js';
import {stateFromHTML} from 'draft-js-import-html';
constructor(props) {
super(props);
var contentState = stateFromHTML(props.input.value);
editorState = EditorState.createWithContent(contentState);
this.state = {editorState: editorState};
}
Above works for me.
@iphonic Thanks for posting, was having problems loading the content stored in the DB back into the editor and your post solved it.
@iphonic Thanks for your answer
@jpuri & @iphonic , I tried statefromHTML and also convertFromHTML from draft-js. both were working fine, but when the content has underline/subscript/superscript content, it was rendered as normal text. Is there any work-around available?
Note: Bold and italic styles working fine.
when the content has underline/subscript/superscript content, it was rendered as normal text
The same problem. Is there any solution?
@iphonic's result worked for me perfectly. I am using functional components though so here is my solution:
const [editorState, setEditorState] = useState(EditorState.createEmpty());
useEffect(() => {
// automatedMessage is the html string I am fetching from my server
if (automatedMessage) {
let contentState = stateFromHTML(automatedMessage.message); //automatedMessage.message being "<p>Test</p>"
setEditorState(EditorState.createWithContent(contentState));
}
}, [automatedMessage]);
Most helpful comment
For ones who are wondering how to initialize it with HTML content instead of empty here is the way you need to generate editorState with the content you have, to init editorState there is a function in draft-js EditorState component and I am using a converter draft-js-import-html which allows to generate contentState out of HTML content, see below
Above works for me.