| categories: [frontend ]
Challenge with Draft JS (Part 1)
One week ago, I had to implement Rich Text editor as one of features in my side project. After searching, I found draft-js which supported
react
very well. It looked so cool. So I decided to integrate it with my project. During that integration and studying, I struggled lots - from setting a simple editor to adding more advanced features for it. It was a really amazing journey to acknowledge myself.
Therefore I want to write down that journey in this series.
Let ’s start.
First Phase - Setup simple editor
Goals
Progress
To be quick, I used create-react-app
to bootstrap the demo app. I read here to know how to install it
$ create-react-app editor-by-draftjs
$ cd editor-by-draftjs
After deps installing finished, I ran below command to make sure It work.
$ npm run start
The app magically automatically opened browser with http://localhost:3000
. At here, I saw the first UI of app
Everything was good until now. I decided to install draft-js
$ npm i draft-js --save
Then I opened my favorite editor - atom
, I created new package at src/Editor/
.
My editor code was put here.
src
| Editor
- Editor.js
- index.js
I put below code into Editor.js
// Editor.js
/*
import draft style
*/
import 'draft-js/dist/Draft.css';
import React, { Component } from react;
import {
Editor,
EditorState
} from 'draft-js';
export default class MyEditor extends Component {
state = {
editorState: EditorState.createEmpty()
}
handleEditorStateChange = (editorState) => {
this.setState({ editorState });
}
render() {
return (
<Editor
editorState={this.state.editorState}
onChange={this.handleEditorStateChange}
placeholder="Tell something you like"
/>
)
}
}
Then I exported to src/Editor/index.js
// index.js
export { default } from './Editor'
Then I included it into src/App.js
// src/App.js
....
render() {
return (
....
<Editor />
....
)
}
....
Tada. Finally, I did it. Simple editor was added.
Goal Completed
Setup a simple editor by `draft-js` (just for writing)
I wondered how to persist the content to db. Hmm, after reading the documentation, I got 2 methods to do that getCurrentContent
& convertToRaw
rawObj = convertToRaw(editorState.getCurrentContent())
rawObj
was a raw javascript object. With it, I could easily to save it to DB.
(Btw there were still another ways to do that. I tried to parse it to markup
or html
before saving it to db by using draft-js-utils.)
But how to parse it again for Editor. Hmm, yah tada, i found convertFromRaw
. With this method, I easily constructed the ContentState
from rawObj
. Then I used EditorState.createWithContent
to construct editorState
editorState = EditorState.createWithContent(convertFromRaw(rawObj))
Goal Completed
How to get content from editor and send it to DB ?
Hmm It was cool until now. But when I press cmd+b
or cmd+i
, nothing happened. Hmmm I thought those keys would be automatically bind, but it was not. So I tried to figure out the way to do that.
Tada, draft-js
supported us to do it by keyBindingFn
and handleKeyCommand
. This was draft-js
’s documentation about it.
// editor.js
import {
Editor,
EditorState,
RichUtils,
getDefaultKeyBinding
} from 'draft-js';
...
/*
Use RichUtils to tunr on shortkey format like CMD+B, CMD+I
*/
handleKeyCommand = (command: string, editorState: EditorState): DraftHandleValue => {
const newState = RichUtils.handleKeyCommand(editorState, command);
if (newState) {
this.handleEditorStateChange(newState);
/*
handled means we already handle this case - no more work need
*/
return 'handled';
}
/*
built-in handlers will be triggered if we return not-handleds
*/
return 'not-handled';
};
...
render() {
return (
<Editor
editorState={this.state.editorState}
onChange={this.handleEditorStateChange}
placeholder="Tell something you like"
keyBindingFn={getDefaultKeyBinding}
handleKeyCommand={this.handleKeyCommand}
/>
)
}
Goal Completed
How to add basic keybindings like `cmd+b`, `cmd+i`, ... ?s
So It was all for the part one. Here is the part 2