- Read Tutorial
- Watch Guide Video
Now, this guide is gonna be a little bit trickier so I definitely recommend for you to pay attention and also to type out all of the code we're gonna type out because we're gonna write a decent amount of code in order to get this functionality working.
The goal is by the end of this guide, you should be able to click on one of these edit icons and it should automatically populate all the data in the form. Now it will not update the images yet, we're going to have to do that separately, but we should be able to update the form by the end of this guide so let's get started on that.
I have the portfolio manager open here and we're gonna create a new function and this is going to allow us to clear our portfolio to edit state item. So here I'm gonna say this.clearPortfolioToEdit equals this.clearPortfolioToEdit and we're gonna bind it to this and then this is gonna be a very basic function.
this.clearPortfolioToEdit = this.clearPortfolioToEdit.bind(this);
It is simply going to do exactly what it says, it's gonna clear that piece of state so it doesn't even need to take in any arguments. We can just say this.setState and then inside of here we're going to take this portfolioToEdit, but this time instead of updating it with a record, we're gonna set it back to its initial state and that is an empty object and you're gonna see why we need to do that here shortly.
portfolio-manager.js
clearPortfolioToEdit() { this.setState({ portfolioToEdit: {} }); }
So now that we have that we need to pass this function and we also need to pass the actual portfolioToEdit as a prop inside of our portfolio form component. So right here let's start by saying clearPortfolioToEdit is going to be a prop and it's just gonna get passed and we'll say this.clearPortfolioToEdit and then we also need to pass the actual data itself.
So this is going to be portfolioToEdit just like this equals now this is not a function, remember this is actually state so here we're gonna say this.state.portfolioToEdit. So hopefully this is making sense on what we're doing here. We're passing a function just like we've been doing and then we're also passing in the portfolioToEdit object.
Now if this is empty, then it's just gonna be an empty object and that's very important because we are going to check against that to see if the portfolioToEdit gets populated or not.
portfolio-manager.js
render() { return ( <div className="portfolio-manager-wrapper"> <div className="left-column"> <PortfolioForm handleSuccessfulFormSubmission={this.handleSuccessfulFormSubmission} handleFormSubmissionError={this.handleFormSubmissionError} clearPortfolioToEdit={this.clearPortfolioToEdit} portfolioToEdit={this.state.portfolioToEdit} /> </div>
So hit save here and now in the portfolio form, we're going to create a new function. This is going to be a lifecycle hook so what we're gonna watch out for is for when the component did update because what we need to listen for is if we're getting those props so if the portfolioToEdit record gets updated, we need to know about it and this is a good lifecycle hook for that.
So I'll say componentDidUpdate and so what we're gonna do is we're going to have a conditional in here and we're going to check to see if the object has keys or not and so this is gonna be something that's not even React related. And let's actually just open up the JavaScript terminal here so that we can see the way this is gonna work.
So let's say that we have two objects so we're gonna have object one and this is going to be just an empty object and then I'm gonna have object two and this is gonna be an object with say a greeting and so here, doesn't really matter what goes inside of it. And so that's all we have, just typical kinda object, we have an object one that's empty, object two that has a greeting.
So how can you tell in JavaScript if an object is empty or not? Well there is a keys property associated with the object so I could say Object.keys and then from here pass in the object so I could pass in say object one right here and then I can from that point call length and that gives us zero so what that means is there are no keys inside of this object which means object is empty.
Now if I take object two, you can see that we get one and so what that is going to tell us is that this object has something inside of it, and that's all we're trying to check inside of our current component is we wanna see does the object or does the portfolioToEdit, is it an empty object or does it have something inside of it because if it has something inside of it, we want to do something?
So you can just copy this if you're following along and typing and what we're gonna do is have a conditional here. So I'm gonna say if and then I can say Object.keys, but obviously we don't have this object two, but what we do have is this.props. and then that portfolioToEdit and then from there I can say .length, then say if that length is greater than zero.
portfolio-form.js
componentDidUpdate() { if (Object.keys(this.props.portfolioToEdit).length > 0) { } }
Then I want to do some work because what this is telling me in componentDidUpdate is that means that say a user clicked right here on the edit button. That's going to trigger componentDidUpdate because we are going to populate that prop and we're going to pass in that data so we're checking to see is there any data there?
If so I first wanna just grab all of the data out, and we're gonna use deconstruction in order to do that. So if you remember the way deconstruction works we're gonna take props and we're going to split up the portfolio item and the portfolio item to edit and the reason I'm gonna do this is because if not you're gonna end up saying something like this.
Where we'll say this.props.portfolioToEdit.id, et cetera, et cetera and you're gonna have to do that for every one of these. But instead, I can say const and then list out all the attributes and I just have them written on the side of the screen so you can just follow along.
We know we have an ID, we have a name, we have a description, a category, a position, a URL and then we have this thumb_image_url, then a banner_image_url and then a logo_url, those are all part of the portfolioToEdit. So I can say all of that inside of the curly brackets and then say this equals this.props.portfolioToEdit. So what that's going to do is it's going to take this object that got passed in and it's going to spread it out. It's going to grab each element and it's gonna store it in a variable just like this.
portfolio-form.js
componentDidUpdate() { if (Object.keys(this.props.portfolioToEdit).length > 0) { const { id, name, description, category, position, url, thumb_image_url, banner_image_url, logo_url } = this.props.portfolioToEdit; } }
Now this is where it gets a little bit tricky. We have all of our data here and we have it stored inside of variables. Now with the way componentDidUpdate works is every single time that a user makes a change such as typing the form, this is going to get fired and that's not good because what that's gonna do is it's gonna clear out our form every single time and it's gonna reset it. So what I wanna do is that's the reason why we have that clear function, this clearPortfolioToEdit function so what we can do is right after we grab all these values is I can call this.props.clearPortfolioToEdit.
That is gonna go into the parent. It's gonna go into the portfolio manager and it's gonna call the clearPortfolioToEdit function so it's going to set this back to its base state of being an empty object and we still get to access all the data, but then when this component changes it's going to skip this because the this.props.portfolioToEdit is gonna be an empty object, so that's a reason why we had to create that.
Okay, so moving on down the line and I know that might be a little bit confusing, but don't worry we're gonna come back and review it because this is one of the trickier parts of this entire section. So if you get this, everything else should hopefully be pretty straightforward.
Okay, now that we have that what we need to do is call this.setState and then from here we need to populate our state so remember we have this portfolio item here. We have all of these cool records here and what we need to do is now setState so each one of those values is then going to be set.
So I can actually just copy that and what I'm going to do here is I'm going to set these values and the very first thing I'm gonna do, we know we're always gonna have an ID and so actually I forgot I need to add this ID value. So we know we're always gonna have the ID and that is the first value that we have up here because every record has that, but not everything is gonna have a name or a description or a category so what we need to do is set up a conditional.
So if there is a name it'll use the name, but if there's not a name it'll use an empty string and the way you can do that in JavaScript is by saying something like name and then we're gonna use the two pipes(|
) and if you're not familiar with using the pipes, that is very similar. It's the or assignment operator or the or operator. They are the key that is right above the return key on the right hand side of your keyboard so those are not Ls, they're not ones, those are the pipe characters and it stands for or.
So what I'm saying here is I want to setState if there is a name so if name actually has a value I want you to store that name, but if name does not, I just want you to add in an empty string. And then we're gonna do this for each of these other ones so I'm gonna say description or an empty string.
Then for category we'll do category just like this or in this case we'll do eCommerce because that's our default. Then for position, then we'll go position or an empty string. URL, may not surprise you we're going to say URL or an empty string.
And then we also right here, we're going to actually, I'm not even gonna set these values right now because we're gonna have a whole set of guides on seeing how we can work with the image value so we can just keep it like this for right now.
portfolio-form.js
this.setState({ id: id, name: name || "", description: description || "", category: category || "eCommerce", position: position || "", url: url || "" });
So I know this looks a little bit confusing, especially if you've never done it before. So we're gonna run through all of this after we ensure that it's working so hit save and come back to Google Chrome, make sure you give it a refresh just to make sure the latest code loaded for sure.
Now if you click on one of your top records you can see the form has updated so that is working perfectly.
I'm gonna scroll down to say DevTrunk here. I'll click on that one and if I scroll up you can see it has the correct name, has the right URL, everything else here is working, all of these other records, even the select field, the dropdown is working.
So that means if that's working for you, that means you've implemented it properly, but let's just kind of cycle through and review exactly what we did because like I said, this is one of the trickier parts of the entire section.
So what we did in the portfolio manager is we created a PortfolioToEdit function and that function does nothing except returns the PortfolioToEdit state to an empty object, that is its only role. Then from there we passed in the PortfolioToEdit and then the clearPortfolioToEdit directly into the portfolio form component so that we have access to it.
And then in the portfolio form we created the componentDidUpdate function which is one of the React lifecycle hooks and then from there we check the portfolioToEdit so we grab the props and we say inside of this portfolioToEdit, is it an empty object? If it is, skip this entire process so if that's the case I don't want you to even look at this code.
But if there is something there, then I want you to drop down inside and I want you to first grab each one of the portfolioToEdit records, each one of those keys, and I'm gonna store those in a local variable, so I'm storing the ID, the name, the description. Everything inside of the portfolioToEdit, I'm storing in its own individual variable and we use destructuring to do that.
Then because I wanna make sure that the portfolioToEdit is no longer inside of the portfolio manager, I'm clearing that value so I'm calling this.props.clearPortfolioToEdit so that it is no longer there and the main reason I'm doing that is so that this does not get fired anymore.
We only want this to happen the first time the user clicks edit on a record, not when they start typing because componentDidUpdate will fire every time there is any change at all occurring in the component and we only want this stuff to happen if the portfolioToEdit actually exists and that means that a user just clicked on it.
So then from thereafter we've cleared that out, then we call this.setState in the local state for our portfolio form and that is how we're grabbing values such as the ID, the name, the description, the category, the position and the URL and later on we'll also grab the images and we'll see how we can work with them.
Then lastly is our little nil check and if you've never heard of a nil check, what it means is that we don't wanna work with nil values so in other words say that you add name here and the name was empty or the description was empty. We don't wanna pass that nil or that null, that empty value into the form because that could be a little bit tricky, that could cause us a few errors.
Instead what we'd rather do is pass in a default value such as an empty string so that's all we're doing here is we're saying if there's a name, put the name in there. If there's not, just put an empty string in there and that's gonna be treated as the default value so this is to protect against errors.
So if you do all of those things, that means you're going to update the local state and then from there you're going to be able to treat all of that data as if it's local just like we've been doing up to this point where a user would go to the form, they would type those values in and it would update the local portfolio item state with ID, the name, the description, all of those values, now this is going to be updated so that we can use it for our own purposes.
So great job if you went through that. I know that can be a little bit on the tricky side so I recommend if it's still fuzzy, go through this video one or two more times until you see exactly the full set of processes that are occurring and then continue on and we'll continue building out the edit functionality.