- Read Tutorial
- Watch Guide Video
Now in order to do this, we're going to have to follow a certain set of steps just like we did anytime we've done any work with the rich text editor because we have to work with the functions and the configuration that they provide.
So that's a reason why I created and isolated this guide because we're gonna have to perform a series of steps and I don't want you to get distracted by some of the other work that we've done up until this point. So we're simply going to dive into what it takes to get the rich text editor programmatically populated.
So let's get started. I'm going to open up the blog form here, the first thing we need to do is to pass a couple props into our blog form. So the first one is gonna be editMode, so I can pass in editMode and then this.props.editMode and remember we're getting those props from the parent blogDetail component, and then we also need to pass the contentToEdit.
So contentToEdit and this is gonna require a ternary operator because we do not wanna pass any details in. We don't wanna pass any content in here if we're not in editMode. So in this case, I'm going to say this.props.editMode and also this.props.blog.content.
So what that's doing is saying I don't want you to pass anything in here if it is not in editMode and if there's not content, 'cause we do have to blogs that do not have content, it's not a required thing that we have in there and I don't wanna end up in this situation where we're passing something like an empty string or anything like that that the API may of returned, I simply wanna return nothing.
So if that's the case, so both of those items are true, then I want to pass in this.props.blog.content, if not, I don't wanna pass anything in. So that's all we need to do in the blog form.
blog-form.js
<div className="one-column"> <RichTextEditor handleRichTextEditorChange={this.handleRichTextEditorChange} editMode={this.props.editMode} contentToEdit={ this.props.editMode && this.props.blog.content ? this.props.blog.content : null } /> </div>
So now opening up the rich text editor, you may see right here that we have this htmlToDraft and we've not used this dependency yet but we imported it a very long time ago, and the reason for that is because we've been waiting for this moment. As the name kind of implies, htmlToDraft takes HTML code, it takes a string of HTML and it imports it into a format that our draft-js function and our component can work with.
So let's start, well, let's first start by importing one more module. So inside of draft-js, make sure that you pull in ContentState, and then let's add a method here. We're gonna add a componentWillMount function so componentWillMount, so we're working with another life cycle hook here, and now we're gonna check to see if we're in editMode and if there's content to edit.
So I can say if this.props.editMode and this.props.contentToEdit, so in other words, that's the reason why I wanted to make sure that we were passing in null if there's no content. If there is content, and if we are in editMode, now we're gonna start this process.
Now these lines of code I'm going to show you, all of these were taken from the draft-js documentation, so everything we're going through, we're simply following the steps needed in order to perform this task and they're the same steps that draft-js recommends us to take.
So first, we're going to grab and parse our HTML. So I'm gonna create a variable here called blocksFromHtml, set this equal to htmlToDraft so we're using that module now, and now we're gonna pass in this.props.contentToEdit because now we are 100% sure that we do have that content and we are in editMode.
So now with that, I'm going to take our blocks and I'm going to split them apart. So what blocksFromHtml does is it will return an object and we're now going to perform some destructuring in order to access that. So I'll say const and then I'm gonna pull out the contentBlocks and then the entityMap and we're pulling that from blocks, I said from but I meant equals and blocksFromHtml. Sometimes when you're coding and talking through it at the same time, your words slide into the code.
rich-text-editor.js
componentWillMount() { if (this.props.editMode && this.props.contentToEdit) { const blocksFromHtml = htmlToDraft(this.props.contentToEdit); const { contentBlocks, entityMap } = blocksFromHtml; } }
Okay so hopefully you can see too, part of the reason why earlier on in the course, I used tools like destructuring and I did in spots where it may not have been needed, you may have thought, oh this is kind of overkill, why are we pulling out these two or three variable names from state? We could've just typed in this.state. whatever the value was.
But the reason why I did that was because when you start to get into more advanced concepts and you start working with libraries, you're gonna see this type of syntax all over the place and I don't want you to see it and you'd be unfamiliar with what we're doing.
So we're performing destructuring here, blocksFromHtml is an object and we're pulling out contentBlocks and entityMap and now we can treat them like they are their own variables.
So the next thing we're gonna do is we're gonna create a contentState. Remember at the very beginning, we pulled in the contentState class from the library from draft-js. Now I'm gonna say const contentState, now this is a variable so make sure you do not capitalize the first C or else you'll run into all kinds of trouble.
And now we are gonna call that library, so I'm gonna say contentState, so this is giving us direct access into draft-js' contentState and I'm gonna say createFromBlockArray. So that is the function that they want you to implement in order to take HTML that you just formatted, that's the reason why we used htmlToDraft, it created this special object that draft-js actually knows what to do with.
We couldn't do this with just a normal string in order to have it parse and render HTML in the text editor, we have to break it up and follow these steps. So I'll say createFromBlocksArray and now we're passing in the contentBlocks and then also the entityMap.
So createFromBlocksArray takes two objects, or it takes two variables and we pass those in and then contentState is gonna be able to work with draft-js and update that state.
So now that we have that, we only have a couple more things to do here. The next is we need to establish the editorState, so I'm going to say const editorState equals EditorState which we have worked with before. I'm going to say I want to createWithContent, so just as a reference point, if you look all the way up at the top here, when we call our rich text editor and we call draft-js, the very first thing we do is we say, I want the editorState to be created but I want it to be empty just like we did here on line 12 while when it's in editMode, we want to establish that editorState but we wanna pass in some content.
That is how you're able to slide in any content to edit and also have it render with the HTML you're wanting. So I'm gonna say createWithContent and here we're passing in contentState and then the very last thing is to set the state so I'll say this.setState and then inside of here, we can just pass in the editorState just like this. Now let's hit save and this should be all we need to do.
rich-text-editor.js
componentWillMount() { if (this.props.editMode && this.props.contentToEdit) { const blocksFromHtml = htmlToDraft(this.props.contentToEdit); const { contentBlocks, entityMap } = blocksFromHtml; const contentState = ContentState.createFromBlockArray( contentBlocks, entityMap ); const editorState = EditorState.createWithContent(contentState); }); } }
So let's test it out, opening up Google Chrome, make sure you give it a refresh, now if I click on Content Page, look at that, it works. We have not only all of our content here, but it's all been split up and all of the HTML that we had in place, such as if you remember, we added italics right here to this word, that has all now been slid in and rendered.
So now every time you click Edit or a user clicks Edit, they don't have to start over with their HTML formatting, that'd be a horrible user experience. Here, we're able to take that, maintain it, place it as a base state in editMode, and that we can work with.
And also, if you wanna test this out with images, if you click on with rich text image here and you look at the post that has that, click on the title and you can see it even renders our HTML images in here.
So this is all working really nicely, great job if you went through all of this and you did it. You now know how to add the base state and work with an edit mode with the draft-js rich text editor and in the next guide, we're gonna start implementing the same type of behavior for our featured image.