- Read Tutorial
- Watch Guide Video
One, our form, whenever a user is typing into it, we want that to update the form's local state. Then from there when the form is submitted we wanna wrap up all of that data and then let the parent component, which in this case is the blog modal, we wanna let it know that the form was submitted.
We're not gonna connect to the API yet or anything like that. Right here, we're simply focusing on state management and on data flow, and being able to have two components that can pass data between themselves. Now, we've already covered every one of these topics several times throughout the course, so hopefully this will be review for you and it's going to, the more times you do it, it's gonna start to feel more and more second nature.
So let's get started, I'm gonna open up Visual Studio Code here and inside of the blog modal component, let's add the function that we wanna pass as a prop for whenever the form has been submitted successfully. So I'm going to come down into the blog modal here and let's first bind the function to this component.
So I'll say this.handleFormSubmission, and if you want, just to make it even more clear, we can say handleSuccessfullFormSubmission and then tie that to this.handleSuccessfullFormSubmission.bind to this and then we can define what we want this function to do.
Right now, all we want it to do is to console.log out a value, but now we are expecting that this function will be passed a blog record. Right now, it's simply gonna be passed some data that we're getting from the form, and in the future, it's going to be passed the response from the API, and then from there, this is going to pass the data back up to the parent blog component and then it will render it on the screen.
But for right now, we'll just assume we're gonna get a blog record and we'll console.log it. So I'll say console.log blog from blog form, and let's see what that data gives us. And then we need to pass this function as a prop directly to our blog form, so let's add that in and let's say that we're passing this.handleSuccessfullFormSubmission, hit save and that's all we need to do in the blog modal.
blog-modal.js
render() { return ( <ReactModal style={this.customStyles} onRequestClose={() => { this.props.handleModalClose(); }} isOpen={this.props.modalIsOpen} > <BlogForm handleSuccessfullFormSubmission={this.handleSuccessfullFormSubmission} /> </ReactModal> ); }
Now, in the blog form, this is where we have quite a bit of code we're gonna write, but all of it is code that we've talked about throughout this course, so let's get to it. The very first thing we're going to do is we need to create a constructor because we need to set a base state because we're going to need to update the component state every time the form is changed and we can capture those values.
So I'm gonna say constructor, we know that we're gonna need props from that parent component, and so we'll call super with props, and then from there, let's define our base state. So say this.state equals, we're going to take in a title, which starts off as an empty string, and then a blog_status, which also starts off as an empty string.
We're not gonna worry about the image or the content yet, and the reason for that is because the image is going to be something we connect with dropzone, so we'll do that later. And then the content is going to use the rich text editor and we're gonna have to work with it a little bit differently, so I'm just going to leave those two off of the form right now.
Now that we have that, let's tie in our handler for watching for when input values change. So I'll say this.handleChange and tie it into this.handleChange.bind this, and now what we can do is define this.
Now, this is the identical code that we used in the portfolio. So I'm going to say handleChange and then inside of here, I'm simply going to say ... for once, actually, let's just do a console.log just to make sure that this is all gonna be wired up correctly, I don't wanna get too far out, and like I've talked about before, run into a bug and then it's gonna take longer to debug it if we don't test it right now.
So let's just say console.log handleChange and then from there, let's just take in whatever the value is. So handleChange takes in an event as its argument automatically and so we can just take a look and see what that event gives us, and then from there, we need to add that to our input. I'm just gonna add it to the very first one, so I'll say onChange equals this.handleChange.
handleChange(event) { console.log("handleChange", event); } render() { return ( <form> <input onChange={this.handleChange} type="text" /> <input type="text" /> <button>Save</button> </form> ); }
Okay, let's hit save and let's see what data we have access to here. Open up the console, and from here on out with the modal, I'm actually gonna move the console here on the right-hand side just so it's a little bit easier to see side-by-side.
So click open modal here and in the very first text box, not in the second one, 'cause we didn't add that change handler yet, just start typing in some code and you can see we're getting all kinds of our synthetic event. So this is working perfectly and so that means we should be able to update our state the way that we want to.
So let me get rid of this console.log here, and you can always reference the portfolio item form, so that you can see how we did this before. We're gonna say this.setState and then pass in what our change is. Now, remember we can't hard code this value because sometimes handleChange is going to be for the title and other times it's gonna be for the blog status.
So this has to be dynamic and that's what we did with the portfolio as well. Whenever you need to do that, and this is a rule in JavaScript, if you need your key to be something that you pass in as a variable, you simply wrap it in the square brackets. So I'll say event.target.name, and then we're gonna say that that is going to be set to event.target.value.
blog-form.js
handleChange(event) {
this.setState({
[event.target.name]: event.target.value
})
}
If that's a little bit fuzzy, then I highly recommend going back and watching the portfolio form guides because we went into quite a bit of depth on what each one of those represented. We walked through the synthetic event object and we saw how we're able to get those values.
But for right now, we're simply taking the setState functions, so we're updating the state every time the form element changes. We're taking the name attribute, which we need to add, and then it's grabbing the values. So let's now come and update our, not our onChange handlers but the actual input events themselves.
So let's move this on multiple lines, the very first one is going to be of type text. So type equals text, we already have our onChange handler so we don't need to make any changes there. Oh, and I didn't even notice we already have that by default, so I'm just gonna get rid of that second one.
So we have onChange, remember we need to add a name attribute, this is how inside of handleChange, this is how we're getting the name. So this is how it knows that this first input should update the title attribute and the second one should update the blog status.
So I'm gonna say name, and then as a string, say title, make sure it's in lower case. It has to match exactly with what we have in the state right here because that's all we're doing, is we're performing a regular lookup, we're saying when the event.target.name is equal to title, set that value, when it's blog status, set it to that second attribute.
So we're gonna say name, title, and then let's add a placeholder just so we know which one is which. So we'll say title or even something like blog title, that's completely up to you, and then we also have to set the value. So value, this one is gonna be dynamic, so we'll say this.state.title, and hit save.
render() { return ( <input type="text" onCange={this.handleChange} name="title" placeholder="Blog Title" value={this.state.title} />
That should be everything that we need and I'm going to get rid of our second input here and let's just copy the entire thing just so you don't have to watch me retype all of it. So the first value is still type text, onChange is the same, the name attribute, though, needs to change to blog_status, and then the placeholder should say blog status, and then the value should be this.state.blog_status.
<input type="text" onChange={this.handleChange} name="blog_status" placeholder="Blog status" value={this.state.blog_status} />
Okay, let's hit save and let's see if this is working. Open up Google Chrome and let's give ourselves a little bit more room and then I'm gonna open up the React Dev Tools 'cause this is how we're gonna be able to look at our state. You also could console.log it, but this is a good practice to get into.
So I'm gonna open this up and let's take a look, we need to, before we inspect, make sure you open up the modal, and then let's take a look at the blog form. So come over here and make sure that you're selecting the correct form element. So I wanna scroll all the way up, we have the modal and then sometimes this inspector can take a little while to find.
Let's see, BlogItems, nope, we don't want any of that. I'm just going to inspect it one more time. There we go, here's our blog form. The Inspector can be very helpful in helping you grab the correct element. So we know we're getting props of handleSuccessfullFormSubmission, and then in state we have blog status and title and these are both empty right now, which is what we would expect because that's our base state.
So come to blog title and just type anything in and you can see our title is getting updated. Go to blog status, type in draft, or published and you can see that is working perfectly, so our state is getting updated exactly the way that we would expect.
So you can close out of the React Dev Tools, open this up, and now the last thing that we're gonna do in this guide is we're going to add our form submission handler. I know this guide is a little longer than the last few ones have been, but because this is all boilerplate code I'd like to finish it in one guide so we can move on to some new topics.
So I'm gonna say form and then I'm gonna pass a onSubmit handler, so this is going to be a function. Now it's a function that we have to actually create up here, so we don't have it yet. So we can call it whatever we want and I'll call it this.handleSubmit and now let's go and create this handleSubmit function.
We'll bind it to this, so handleSubmit is equal to this.handleSubmit.bind this and now in the function itself I'm gonna say handleSubmit, we're going to get the event and remember what we do with the event with the form submission process is we always call event.preventDefault and that is a pure Vanilla JavaScript function that makes it possible for the form to be submitted, but the page will not refresh.
You just have that at the very bottom of that function and besides that, we simply need to now call our prop. So from blog modal, we passed in handleSuccessfullFormSubmission. So we're gonna call this.props.handleSuccessfullFormSubmission and we need to pass in the blog.
Now, remember we will eventually be passing in the response from the API. For right now let's just pass in this.state so that we can see our state object and make sure that we're getting it, it's updating it, and we can pass it up to the parent component.
blog-form.js
this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleSubmit(event) { this.props.handleSuccessfullFormSubmission(this.state); event.preventDefault(); } handleChange(event) { this.setState({ [event.target.name]: event.target.value }); } render() { return ( <form onSubmit={this.handleSubmit}> <input type="text" onChange={this.handleChange} name="title" placeholder="Blog Title" value={this.state.title} />
Okay, that was a lot of code to write in a single guide, so let's make sure that everything is working and then we can move on in the next guide.
So I'm going to open up the JavaScript console here, make sure you hit refresh and then inside of the open modal you can type anything you want into these values, click on save, and you can see here in the JavaScript console this is working, because this is the console.log from our parent component, from the modal itself, and we're getting the title and the blog status and these are both accurate.
So we have now successfully added all of the form boilerplate and we have our two key listeners. We have the handleChange listener, which is watching for changes in the form and then we have the onSubmit listener, which is going to be our process for calling the API eventually, but for right now passing the data up to the parent component.
So great job, we now have a functional form and in the next few guides, we will start building this out extending it so that the form communicates with the API and eventually populates the data.