Andrew Burns
Andrew Burns

Reputation: 309

Draft-js editors causing reversed input

I've got an application that requires multiple text inputs, and for formatting and customization I've chosen draft-js as my editor, however I've come across a very bewildering input issue.

When I type into the editors, my most recently pressed key is printed at the beginning of the editor, reversing my entire input, as if the caret is always at the first index of the line.

I have 3 editors, each one has an onChange, that updates a redux store with the editors current contentState. When the page is re-rendered, each editor is then rendered with their respective contentState transformed into an EditorState.

Here is my code:

main.js

render() {

    /* Each Editor has a similar block as below */

    let coverEditorState = EditorState.createEmpty()
    let coverContentState = _.get(data, 'details.message.cover.contentState')

    if (typeof coverContentHTML != "undefined"){
        coverEditorState = EditorState.createWithContent(coverContentState)
    }

    return (
        ...
        <Composer
            editorState={coverEditorState}
            onChange={this._handleCoveringLetterChange.bind(this)}
        />
        ...
    )
}

Composer.js

class Composer extends Component {
    constructor() {
        super()
        this.state = { editorState: EditorState.createEmpty(), styleMap: {} }
    }

    componentWillReceiveProps( nextProps ) {
        this.setState({ editorState: nextProps.editorState })
    }

    onChange( editorState ) {

        let nextState = Object.assign({}, this.state, { editorState })

        let currentContentState = editorState.getCurrentContent()

        let changeObject = {
            contentState: currentContentState
        }

        this.setState(nextState)
        this.props.onChange(changeObject)
    }

    render() {
        return (
            <Editor 
                editorState={this.state.editorState}
                onChange={this.onChange.bind(this)}
            />
        )
    }
}

I've tried returning the SelectionState as well as the ContentState, combining the two, and re-rendering, but that only leads to more problems and errors.

Upvotes: 3

Views: 2281

Answers (2)

Craig B
Craig B

Reputation: 19

I've just hit (and resolved) a similar problem.

If you're having the same problem as me, it's because the call to setState actually queues an update to the state, and it's not being applied before the call to this.props.onChange. This understandably seems to throw draft.js out of whack.

Try changing:

this.setState(nextState)
this.props.onChange(changeObject)

to:

this.setState(nextState, () => { 
    this.props.onChange(changeObject); 
});

This will ensure the state is updated before calling the parent onChange callback.

Upvotes: 1

tobiasandersen
tobiasandersen

Reputation: 8688

I can't really see by the code you've provided, but it sounds like your problem is that you're recreating the EditorState (using EditorState.createEmpty() or EditorState.createWithContetnt()) on each change. That won't work, since it's only restoring the content — not the cursor position, selection, etc.

The way I've solved it, is that I create the EditorState only once, i.e. if it doesn't already exist. Then, on each change, I update the EditorState normally and, at the same time, save the contentState to, in our case, the database. The important thing here is that you don't use the contentState to create a new EditorState.

So the next time the EditorState doesn't exist, it gets initialized using EditorState.createWithContent(contentStateFromDB).

Upvotes: 0

Related Questions