I have a site where we are using multiple forms on the same page. I have used Draftjs with react to create rich html text inputs, which I have customized to use only the controls I actually need:
class RichEditor extends React.Component {
constructor(props) {
super(props);
this.state = {editorState: EditorState.createEmpty()};
this.focus = () => this.refs.editor.focus();
this.onChange = (editorState) => {
this.setState({editorState});
}
this.handleKeyCommand = (command) => this._handleKeyCommand(command);
this.onTab = (e) => this._onTab(e);
this.toggleBlockType = (type) => this._toggleBlockType(type);
this.toggleInlineStyle = (style) => this._toggleInlineStyle(style);
}
_handleKeyCommand(command) {
const {editorState} = this.state;
const newState = RichUtils.handleKeyCommand(editorState, command);
if (newState) {
this.onChange(newState);
return true;
}
return false;
}
_onTab(e) {
const maxDepth = 4;
this.onChange(RichUtils.onTab(e, this.state.editorState, maxDepth));
}
_toggleBlockType(blockType) {
this.onChange(
RichUtils.toggleBlockType(
this.state.editorState,
blockType
)
);
}
_toggleInlineStyle(inlineStyle) {
this.onChange(
RichUtils.toggleInlineStyle(
this.state.editorState,
inlineStyle
)
);
}
render() {
const { editorState } = this.state;
let className = 'RichEditor-editor';
var contentState = editorState.getCurrentContent();
if (!contentState.hasText()) {
if (contentState.getBlockMap().first().getType() !== 'unstyled') {
className += ' RichEditor-hidePlaceholder';
}
}
return (
<div className="RichEditor-root">
<BlockStyleControls
editorState={editorState}
onToggle={this.toggleBlockType}
/>
<InlineStyleControls
editorState={editorState}
onToggle={this.toggleInlineStyle}
/>
<div className={className} onClick={this.focus}>
<Editor
blockStyleFn={getBlockStyle}
customStyleMap={styleMap}
editorState={editorState}
handleKeyCommand={this.handleKeyCommand}
onChange={this.onChange}
onTab={this.onTab}
placeholder=""
ref="editor"
spellCheck={true}
/>
</div>
</div>
);
}
}
module.exports = RichEditor
My parent component looks like this:
class WrapperComponent extends React.Component {
constructor(props) {
super(props);
this.onChange = (editorState2) => {
this.setState({editorState2});
console.log("onChange");
console.log(editorState2);
}
this.state = {
editorState1: EditorState.createEmpty(),
editorState2: EditorState.createEmpty(),
html: null
}
}
update() {
console.log("update");
console.log(this.state.editorState2);
console.log(convertToRaw(this.state.editorState2.getCurrentContent()));
//this.setState({ draftEditor2: e.value });
this.setState({ html: stateToHTML(this.state.editorState2.getCurrentContent()) });
}
render () {
const Editable = () => (
<div className="editor">
<div className="editor-inner">
<h3>Redigerar: Anbudsbrev</h3>
<h4>Rubrik</h4>
<input type="text" name="title" />
<h4>Text 1</h4>
<RichEditor editorState={this.state.editorState1} updateStateToParent={this.onChange} name="text01" ref="editor" />
<h4>Citat</h4>
<input type="text" name="quote01" />
<h4>Text 2</h4>
<RichEditor updateStateToParent={this.onChange} name="text02" ref="editor" />
<EditorFooter {...this.props} submitForm={this.submitForm} />
<button onClick={this.update.bind(this)}>Update</button>
<div>{this.state.html}</div>
</div>
</div>
);
const Readable = () => (
<div>
<h1 className="header66">{this.props.title}</h1>
<div className="text66">{this.props.text01}</div>
<div className="quote100">{this.props.quote01}</div>
<div className="text66">{this.props.text02}</div>
</div>
);
return (
<div>
{ this.props.isInEditMode ? <Editable /> : <Readable /> }
</div>
);
}
};
WrapperComponent.defaultProps = {
height: 100,
title: "Lorem ipsum dolor sit amet",
text01: "Mauris sollicitudin purus accumsan libero fringilla, vitae vulputate lorem aliquam. Nunc ipsum nisl, consectetur ac ultrices ac, pretium vitae lectus. Cras vestibulum, arcu non condimentum hendrerit, dolor ante molestie ante, eget dapibus felis quam a ante. Nunc fringilla risus eget nunc tincidunt sodales.",
quote01: "Aliquam erat volutpat.",
text02: "Praesent non erat quis sem mollis sodales. Integer convallis metus in ligula vehicula, quis vulputate lectus accumsan. Aliquam luctus posuere mollis. Aliquam luctus dignissim quam, ut aliquet ligula pellentesque ac. Nulla sodales lacus sem, eu pharetra arcu aliquet ac. Sed in venenatis libero."
};
WrapperComponent.propTypes = {
content: PropTypes.object,
itemId: PropTypes.string
}
module.exports = WrapperComponent
But I seem to be misunderstanding something fundamental. I can't get the value from either of the editors.
If I send updateStateToParent
to my RichEditor
I can see some stuff happening, but I can't grab the state from the RichEditor
and add it to the state of the WrapperComponent
.
I think I am approaching this in the wrong way, but I can't get my head around how to solve it.
I think you're pretty close here, but the problem is that you aren't using the parent to set the editorStates. What you should do is storing and updating the editorStates inside your parent component.
This means that the RichEditor
-component must:
Here's a minimal example:
class RichEditor extends React.Component {
render() {
const { editorState, onChange } = this.props;
return (
<div style={{ background: 'white' }}>
<Editor editorState={editorState} onChange={onChange} />
</div>
);
}
}
The parent in its turn must:
RichEditor
(and pass them down)Here's a minimal example of that:
class WrapperComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
editorState1: EditorState.createEmpty(),
editorState2: EditorState.createEmpty()
}
}
onChange = (editorStateKey) => (editorState) => {
this.setState({ [editorStateKey]: editorState });
}
render () {
return (
<div>
<h4>Editor 1</h4>
<RichEditor editorState={this.state.editorState1} onChange={this.onChange('editorState1')} />
<h4>Editor 2</h4>
<RichEditor editorState={this.state.editorState2} onChange={this.onChange('editorState2')} />
</div>
)
}
};
And finally, here's a working fiddle: https://jsfiddle.net/bwk32xuo/